Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
68a1618743 changed things to include plog 2024-01-22 12:05:59 +01:00
34 changed files with 2702 additions and 27 deletions

View file

@ -2,14 +2,8 @@
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"includePath": ["${workspaceFolder}/**"],
"defines": ["_DEBUG", "UNICODE", "_UNICODE"],
"compilerPath": "C:\\msys64\\mingw64\\bin\\gcc.exe",
"cStandard": "c17",
"cppStandard": "gnu++20",
@ -17,4 +11,4 @@
}
],
"version": 4
}
}

View file

@ -4,7 +4,7 @@
"name": "Debug: C/C++",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\build\\${fileBasenameNoExtension}.exe",
"program": "${workspaceFolder}\\build\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
@ -30,7 +30,7 @@
"name": "Release: C/C++",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}\\build\\${fileBasenameNoExtension}.exe",
"program": "${workspaceFolder}\\build\\${fileBasenameNoExtension}.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",

View file

@ -6,12 +6,13 @@
"command": "C:\\msys64\\mingw64\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-I${workspaceFolder}\\include",
"-ggdb",
"-std=c++20",
"-pedantic-errors",
"${fileDirname}/**.cpp",
"${workspaceFolder}/src/**.cpp",
"-o",
"${fileDirname}\\build\\${fileBasenameNoExtension}.exe"
"${workspaceFolder}\\build\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"
@ -26,13 +27,14 @@
"command": "C:\\msys64\\mingw64\\bin\\g++.exe",
"args": [
"-fdiagnostics-color=always",
"-I${workspaceFolder}\\include",
"-O2",
"-DNDEBUG",
"-std=c++20",
"-pedantic-errors",
"${fileDirname}/**.cpp",
"${workspaceFolder}/src/**.cpp",
"-o",
"${fileDirname}\\build\\${fileBasenameNoExtension}.exe"
"${workspaceFolder}\\build\\${fileBasenameNoExtension}.exe"
],
"options": {
"cwd": "${fileDirname}"

View file

@ -0,0 +1,47 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <android/log.h>
namespace plog
{
template<class Formatter>
class PLOG_LINKAGE_HIDDEN AndroidAppender : public IAppender
{
public:
AndroidAppender(const char* tag) : m_tag(tag)
{
}
virtual void write(const Record& record) PLOG_OVERRIDE
{
std::string str = Formatter::format(record);
__android_log_print(toPriority(record.getSeverity()), m_tag, "%s", str.c_str());
}
private:
static android_LogPriority toPriority(Severity severity)
{
switch (severity)
{
case fatal:
return ANDROID_LOG_FATAL;
case error:
return ANDROID_LOG_ERROR;
case warning:
return ANDROID_LOG_WARN;
case info:
return ANDROID_LOG_INFO;
case debug:
return ANDROID_LOG_DEBUG;
case verbose:
return ANDROID_LOG_VERBOSE;
default:
return ANDROID_LOG_UNKNOWN;
}
}
private:
const char* const m_tag;
};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <Arduino.h>
namespace plog
{
template<class Formatter>
class PLOG_LINKAGE_HIDDEN ArduinoAppender : public IAppender
{
public:
ArduinoAppender(Stream &stream) : m_stream(stream)
{
}
virtual void write(const Record &record) PLOG_OVERRIDE
{
m_stream.print(Formatter::format(record).c_str());
}
private:
Stream &m_stream;
};
}

View file

@ -0,0 +1,108 @@
#pragma once
#include <plog/Appenders/ConsoleAppender.h>
#include <plog/WinApi.h>
namespace plog
{
template<class Formatter>
class PLOG_LINKAGE_HIDDEN ColorConsoleAppender : public ConsoleAppender<Formatter>
{
public:
#ifdef _WIN32
# ifdef _MSC_VER
# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum'
# endif
ColorConsoleAppender(OutputStream outStream = streamStdOut)
: ConsoleAppender<Formatter>(outStream)
, m_originalAttr()
{
if (this->m_isatty)
{
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
GetConsoleScreenBufferInfo(this->m_outputHandle, &csbiInfo);
m_originalAttr = csbiInfo.wAttributes;
}
}
#else
ColorConsoleAppender(OutputStream outStream = streamStdOut)
: ConsoleAppender<Formatter>(outStream)
{}
#endif
virtual void write(const Record& record) PLOG_OVERRIDE
{
util::nstring str = Formatter::format(record);
util::MutexLock lock(this->m_mutex);
setColor(record.getSeverity());
this->writestr(str);
resetColor();
}
protected:
void setColor(Severity severity)
{
if (this->m_isatty)
{
switch (severity)
{
#ifdef _WIN32
case fatal:
SetConsoleTextAttribute(this->m_outputHandle, foreground::kRed | foreground::kGreen | foreground::kBlue | foreground::kIntensity | background::kRed); // white on red background
break;
case error:
SetConsoleTextAttribute(this->m_outputHandle, static_cast<WORD>(foreground::kRed | foreground::kIntensity | (m_originalAttr & 0xf0))); // red
break;
case warning:
SetConsoleTextAttribute(this->m_outputHandle, static_cast<WORD>(foreground::kRed | foreground::kGreen | foreground::kIntensity | (m_originalAttr & 0xf0))); // yellow
break;
case debug:
case verbose:
SetConsoleTextAttribute(this->m_outputHandle, static_cast<WORD>(foreground::kGreen | foreground::kBlue | foreground::kIntensity | (m_originalAttr & 0xf0))); // cyan
break;
#else
case fatal:
this->m_outputStream << "\x1B[97m\x1B[41m"; // white on red background
break;
case error:
this->m_outputStream << "\x1B[91m"; // red
break;
case warning:
this->m_outputStream << "\x1B[93m"; // yellow
break;
case debug:
case verbose:
this->m_outputStream << "\x1B[96m"; // cyan
break;
#endif
default:
break;
}
}
}
void resetColor()
{
if (this->m_isatty)
{
#ifdef _WIN32
SetConsoleTextAttribute(this->m_outputHandle, m_originalAttr);
#else
this->m_outputStream << "\x1B[0m\x1B[0K";
#endif
}
}
private:
#ifdef _WIN32
WORD m_originalAttr;
#endif
};
}

View file

@ -0,0 +1,83 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <plog/Util.h>
#include <plog/WinApi.h>
#include <iostream>
namespace plog
{
enum OutputStream
{
streamStdOut,
streamStdErr
};
template<class Formatter>
class PLOG_LINKAGE_HIDDEN ConsoleAppender : public IAppender
{
public:
#ifdef _WIN32
# ifdef _MSC_VER
# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum'
# endif
ConsoleAppender(OutputStream outStream = streamStdOut)
: m_isatty(!!_isatty(_fileno(outStream == streamStdOut ? stdout : stderr)))
, m_outputStream(outStream == streamStdOut ? std::cout : std::cerr)
, m_outputHandle()
{
if (m_isatty)
{
m_outputHandle = GetStdHandle(outStream == streamStdOut ? stdHandle::kOutput : stdHandle::kErrorOutput);
}
}
#else
ConsoleAppender(OutputStream outStream = streamStdOut)
: m_isatty(!!isatty(fileno(outStream == streamStdOut ? stdout : stderr)))
, m_outputStream(outStream == streamStdOut ? std::cout : std::cerr)
{}
#endif
virtual void write(const Record& record) PLOG_OVERRIDE
{
util::nstring str = Formatter::format(record);
util::MutexLock lock(m_mutex);
writestr(str);
}
protected:
void writestr(const util::nstring& str)
{
#ifdef _WIN32
if (m_isatty)
{
const std::wstring& wstr = util::toWide(str);
WriteConsoleW(m_outputHandle, wstr.c_str(), static_cast<DWORD>(wstr.size()), NULL, NULL);
}
else
{
# if PLOG_CHAR_IS_UTF8
m_outputStream << str << std::flush;
# else
m_outputStream << util::toNarrow(str, codePage::kActive) << std::flush;
# endif
}
#else
m_outputStream << str << std::flush;
#endif
}
private:
#ifdef __BORLANDC__
static int _isatty(int fd) { return ::isatty(fd); }
#endif
protected:
util::Mutex m_mutex;
const bool m_isatty;
std::ostream& m_outputStream;
#ifdef _WIN32
HANDLE m_outputHandle;
#endif
};
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <plog/WinApi.h>
namespace plog
{
template<class Formatter>
class PLOG_LINKAGE_HIDDEN DebugOutputAppender : public IAppender
{
public:
virtual void write(const Record& record) PLOG_OVERRIDE
{
OutputDebugStringW(util::toWide(Formatter::format(record)).c_str());
}
};
}

View file

@ -0,0 +1,42 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <set>
namespace plog
{
class PLOG_LINKAGE_HIDDEN DynamicAppender : public IAppender
{
public:
DynamicAppender& addAppender(IAppender* appender)
{
assert(appender != this);
util::MutexLock lock(m_mutex);
m_appenders.insert(appender);
return *this;
}
DynamicAppender& removeAppender(IAppender* appender)
{
util::MutexLock lock(m_mutex);
m_appenders.erase(appender);
return *this;
}
virtual void write(const Record& record) PLOG_OVERRIDE
{
util::MutexLock lock(m_mutex);
for (std::set<IAppender*>::iterator it = m_appenders.begin(); it != m_appenders.end(); ++it)
{
(*it)->write(record);
}
}
private:
mutable util::Mutex m_mutex;
std::set<IAppender*> m_appenders;
};
}

View file

@ -0,0 +1,117 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <plog/WinApi.h>
namespace plog
{
template <class Formatter>
class PLOG_LINKAGE_HIDDEN EventLogAppender : public IAppender
{
public:
EventLogAppender(const util::nchar* sourceName) : m_eventSource(RegisterEventSourceW(NULL, util::toWide(sourceName).c_str()))
{
}
~EventLogAppender()
{
DeregisterEventSource(m_eventSource);
}
virtual void write(const Record& record) PLOG_OVERRIDE
{
util::nstring str = Formatter::format(record);
write(record.getSeverity(), util::toWide(str).c_str());
}
private:
void write(Severity severity, const wchar_t* str)
{
const wchar_t* logMessagePtr[] = { str };
ReportEventW(m_eventSource, logSeverityToType(severity), static_cast<WORD>(severity), 0, NULL, 1, 0, logMessagePtr, NULL);
}
static WORD logSeverityToType(plog::Severity severity)
{
switch (severity)
{
case plog::fatal:
case plog::error:
return eventLog::kErrorType;
case plog::warning:
return eventLog::kWarningType;
case plog::info:
case plog::debug:
case plog::verbose:
default:
return eventLog::kInformationType;
}
}
private:
HANDLE m_eventSource;
};
class EventLogAppenderRegistry
{
public:
static bool add(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application"))
{
std::wstring logKeyName;
std::wstring sourceKeyName;
getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
HKEY sourceKey;
if (0 != RegCreateKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, NULL, 0, regSam::kSetValue, NULL, &sourceKey, NULL))
{
return false;
}
const DWORD kTypesSupported = eventLog::kErrorType | eventLog::kWarningType | eventLog::kInformationType;
RegSetValueExW(sourceKey, L"TypesSupported", 0, regType::kDword, reinterpret_cast<const BYTE*>(&kTypesSupported), sizeof(kTypesSupported));
const wchar_t kEventMessageFile[] = L"%windir%\\Microsoft.NET\\Framework\\v4.0.30319\\EventLogMessages.dll;%windir%\\Microsoft.NET\\Framework\\v2.0.50727\\EventLogMessages.dll";
RegSetValueExW(sourceKey, L"EventMessageFile", 0, regType::kExpandSz, reinterpret_cast<const BYTE*>(kEventMessageFile), sizeof(kEventMessageFile) - sizeof(*kEventMessageFile));
RegCloseKey(sourceKey);
return true;
}
static bool exists(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application"))
{
std::wstring logKeyName;
std::wstring sourceKeyName;
getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
HKEY sourceKey;
if (0 != RegOpenKeyExW(hkey::kLocalMachine, sourceKeyName.c_str(), 0, regSam::kQueryValue, &sourceKey))
{
return false;
}
RegCloseKey(sourceKey);
return true;
}
static void remove(const util::nchar* sourceName, const util::nchar* logName = PLOG_NSTR("Application"))
{
std::wstring logKeyName;
std::wstring sourceKeyName;
getKeyNames(sourceName, logName, sourceKeyName, logKeyName);
RegDeleteKeyW(hkey::kLocalMachine, sourceKeyName.c_str());
RegDeleteKeyW(hkey::kLocalMachine, logKeyName.c_str());
}
private:
static void getKeyNames(const util::nchar* sourceName, const util::nchar* logName, std::wstring& sourceKeyName, std::wstring& logKeyName)
{
const std::wstring kPrefix = L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\";
logKeyName = kPrefix + util::toWide(logName);
sourceKeyName = logKeyName + L"\\" + util::toWide(sourceName);
}
};
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <plog/Record.h>
#include <plog/Util.h>
namespace plog
{
class PLOG_LINKAGE IAppender
{
public:
virtual ~IAppender()
{
}
virtual void write(const Record& record) = 0;
};
}

View file

@ -0,0 +1,148 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <plog/Converters/UTF8Converter.h>
#include <plog/Converters/NativeEOLConverter.h>
#include <plog/Util.h>
#include <algorithm>
namespace plog
{
template<class Formatter, class Converter = NativeEOLConverter<UTF8Converter> >
class PLOG_LINKAGE_HIDDEN RollingFileAppender : public IAppender
{
public:
RollingFileAppender(const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8
RollingFileAppender(const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
: m_fileSize()
, m_maxFileSize()
, m_maxFiles(maxFiles)
, m_firstWrite(true)
{
setFileName(fileName);
setMaxFileSize(maxFileSize);
}
#endif
virtual void write(const Record& record) PLOG_OVERRIDE
{
util::MutexLock lock(m_mutex);
if (m_firstWrite)
{
openLogFile();
m_firstWrite = false;
}
else if (m_maxFiles > 0 && m_fileSize > m_maxFileSize && static_cast<size_t>(-1) != m_fileSize)
{
rollLogFiles();
}
size_t bytesWritten = m_file.write(Converter::convert(Formatter::format(record)));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
void setFileName(const util::nchar* fileName)
{
util::MutexLock lock(m_mutex);
util::splitFileName(fileName, m_fileNameNoExt, m_fileExt);
m_file.close();
m_firstWrite = true;
}
#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8
void setFileName(const char* fileName)
{
setFileName(util::toWide(fileName).c_str());
}
#endif
void setMaxFiles(int maxFiles)
{
m_maxFiles = maxFiles;
}
void setMaxFileSize(size_t maxFileSize)
{
m_maxFileSize = (std::max)(maxFileSize, static_cast<size_t>(1000)); // set a lower limit for the maxFileSize
}
void rollLogFiles()
{
m_file.close();
util::nstring lastFileName = buildFileName(m_maxFiles - 1);
util::File::unlink(lastFileName);
for (int fileNumber = m_maxFiles - 2; fileNumber >= 0; --fileNumber)
{
util::nstring currentFileName = buildFileName(fileNumber);
util::nstring nextFileName = buildFileName(fileNumber + 1);
util::File::rename(currentFileName, nextFileName);
}
openLogFile();
m_firstWrite = false;
}
private:
void openLogFile()
{
m_fileSize = m_file.open(buildFileName());
if (0 == m_fileSize)
{
size_t bytesWritten = m_file.write(Converter::header(Formatter::header()));
if (static_cast<size_t>(-1) != bytesWritten)
{
m_fileSize += bytesWritten;
}
}
}
util::nstring buildFileName(int fileNumber = 0)
{
util::nostringstream ss;
ss << m_fileNameNoExt;
if (fileNumber > 0)
{
ss << '.' << fileNumber;
}
if (!m_fileExt.empty())
{
ss << '.' << m_fileExt;
}
return ss.str();
}
private:
util::Mutex m_mutex;
util::File m_file;
size_t m_fileSize;
size_t m_maxFileSize;
int m_maxFiles;
util::nstring m_fileExt;
util::nstring m_fileNameNoExt;
bool m_firstWrite;
};
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <plog/Converters/UTF8Converter.h>
#include <plog/Util.h>
namespace plog
{
template<class NextConverter = UTF8Converter>
class NativeEOLConverter : public NextConverter
{
#ifdef _WIN32
public:
static std::string header(const util::nstring& str)
{
return NextConverter::header(fixLineEndings(str));
}
static std::string convert(const util::nstring& str)
{
return NextConverter::convert(fixLineEndings(str));
}
private:
static util::nstring fixLineEndings(const util::nstring& str)
{
util::nstring output;
output.reserve(str.length() * 2); // the worst case requires 2x chars
for (size_t i = 0; i < str.size(); ++i)
{
util::nchar ch = str[i];
if (ch == PLOG_NSTR('\n'))
{
output.push_back(PLOG_NSTR('\r'));
}
output.push_back(ch);
}
return output;
}
#endif
};
}

View file

@ -0,0 +1,28 @@
#pragma once
#include <plog/Util.h>
namespace plog
{
class UTF8Converter
{
public:
static std::string header(const util::nstring& str)
{
const char kBOM[] = "\xEF\xBB\xBF";
return std::string(kBOM) + convert(str);
}
#if PLOG_CHAR_IS_UTF8
static const std::string& convert(const util::nstring& str)
{
return str;
}
#else
static std::string convert(const util::nstring& str)
{
return util::toNarrow(str, codePage::kUTF8);
}
#endif
};
}

View file

@ -0,0 +1,57 @@
#pragma once
#include <plog/Record.h>
#include <plog/Util.h>
#include <iomanip>
namespace plog
{
template<bool useUtcTime>
class CsvFormatterImpl
{
public:
static util::nstring header()
{
return PLOG_NSTR("Date;Time;Severity;TID;This;Function;Message\n");
}
static util::nstring format(const Record& record)
{
tm t;
useUtcTime ? util::gmtime_s(&t, &record.getTime().time) : util::localtime_s(&t, &record.getTime().time);
util::nostringstream ss;
ss << t.tm_year + 1900 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("/") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(";");
ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << static_cast<int> (record.getTime().millitm) << PLOG_NSTR(";");
ss << severityToString(record.getSeverity()) << PLOG_NSTR(";");
ss << record.getTid() << PLOG_NSTR(";");
ss << record.getObject() << PLOG_NSTR(";");
ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(";");
util::nstring message = record.getMessage();
if (message.size() > kMaxMessageSize)
{
message.resize(kMaxMessageSize);
message.append(PLOG_NSTR("..."));
}
util::nistringstream split(message);
util::nstring token;
while (!split.eof())
{
std::getline(split, token, PLOG_NSTR('"'));
ss << PLOG_NSTR("\"") << token << PLOG_NSTR("\"");
}
ss << PLOG_NSTR("\n");
return ss.str();
}
static const size_t kMaxMessageSize = 32000;
};
class CsvFormatter : public CsvFormatterImpl<false> {};
class CsvFormatterUtcTime : public CsvFormatterImpl<true> {};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <plog/Record.h>
#include <plog/Util.h>
namespace plog
{
class FuncMessageFormatter
{
public:
static util::nstring header()
{
return util::nstring();
}
static util::nstring format(const Record& record)
{
util::nostringstream ss;
ss << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR(": ") << record.getMessage() << PLOG_NSTR("\n");
return ss.str();
}
};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <plog/Record.h>
#include <plog/Util.h>
namespace plog
{
class MessageOnlyFormatter
{
public:
static util::nstring header()
{
return util::nstring();
}
static util::nstring format(const Record& record)
{
util::nostringstream ss;
ss << record.getMessage() << PLOG_NSTR("\n");
return ss.str();
}
};
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <plog/Record.h>
#include <plog/Util.h>
#include <iomanip>
namespace plog
{
template<bool useUtcTime>
class TxtFormatterImpl
{
public:
static util::nstring header()
{
return util::nstring();
}
static util::nstring format(const Record& record)
{
tm t;
useUtcTime ? util::gmtime_s(&t, &record.getTime().time) : util::localtime_s(&t, &record.getTime().time);
util::nostringstream ss;
ss << t.tm_year + 1900 << "-" << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mon + 1 << PLOG_NSTR("-") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_mday << PLOG_NSTR(" ");
ss << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_hour << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_min << PLOG_NSTR(":") << std::setfill(PLOG_NSTR('0')) << std::setw(2) << t.tm_sec << PLOG_NSTR(".") << std::setfill(PLOG_NSTR('0')) << std::setw(3) << static_cast<int> (record.getTime().millitm) << PLOG_NSTR(" ");
ss << std::setfill(PLOG_NSTR(' ')) << std::setw(5) << std::left << severityToString(record.getSeverity()) << PLOG_NSTR(" ");
ss << PLOG_NSTR("[") << record.getTid() << PLOG_NSTR("] ");
ss << PLOG_NSTR("[") << record.getFunc() << PLOG_NSTR("@") << record.getLine() << PLOG_NSTR("] ");
ss << record.getMessage() << PLOG_NSTR("\n");
return ss.str();
}
};
class TxtFormatter : public TxtFormatterImpl<false> {};
class TxtFormatterUtcTime : public TxtFormatterImpl<true> {};
}

View file

@ -0,0 +1,40 @@
#pragma once
#include <plog/Util.h>
#include <cctype>
namespace plog
{
class AscDump
{
public:
AscDump(const void* ptr, size_t size)
: m_ptr(static_cast<const char*>(ptr))
, m_size(size)
{
}
friend util::nostringstream& operator<<(util::nostringstream& stream, const AscDump& ascDump);
private:
const char* m_ptr;
size_t m_size;
};
inline util::nostringstream& operator<<(util::nostringstream& stream, const AscDump& ascDump)
{
for (size_t i = 0; i < ascDump.m_size; ++i)
{
stream << (std::isprint(ascDump.m_ptr[i]) ? ascDump.m_ptr[i] : '.');
}
return stream;
}
inline AscDump ascdump(const void* ptr, size_t size) { return AscDump(ptr, size); }
template<class Container>
inline AscDump ascdump(const Container& container) { return AscDump(container.data(), container.size() * sizeof(*container.data())); }
template<class T, size_t N>
inline AscDump ascdump(const T (&arr)[N]) { return AscDump(arr, N * sizeof(*arr)); }
}

View file

@ -0,0 +1,79 @@
#pragma once
#include <plog/Util.h>
#include <iomanip>
namespace plog
{
class HexDump
{
public:
HexDump(const void* ptr, size_t size)
: m_ptr(static_cast<const unsigned char*>(ptr))
, m_size(size)
, m_group(8)
, m_digitSeparator(" ")
, m_groupSeparator(" ")
{
}
HexDump& group(size_t group)
{
m_group = group;
return *this;
}
HexDump& separator(const char* digitSeparator)
{
m_digitSeparator = digitSeparator;
return *this;
}
HexDump& separator(const char* digitSeparator, const char* groupSeparator)
{
m_digitSeparator = digitSeparator;
m_groupSeparator = groupSeparator;
return *this;
}
friend util::nostringstream& operator<<(util::nostringstream& stream, const HexDump&);
private:
const unsigned char* m_ptr;
size_t m_size;
size_t m_group;
const char* m_digitSeparator;
const char* m_groupSeparator;
};
inline util::nostringstream& operator<<(util::nostringstream& stream, const HexDump& hexDump)
{
stream << std::hex << std::setfill(PLOG_NSTR('0'));
for (size_t i = 0; i < hexDump.m_size;)
{
stream << std::setw(2) << static_cast<int>(hexDump.m_ptr[i]);
if (++i < hexDump.m_size)
{
if (hexDump.m_group > 0 && i % hexDump.m_group == 0)
{
stream << hexDump.m_groupSeparator;
}
else
{
stream << hexDump.m_digitSeparator;
}
}
}
return stream;
}
inline HexDump hexdump(const void* ptr, size_t size) { return HexDump(ptr, size); }
template<class Container>
inline HexDump hexdump(const Container& container) { return HexDump(container.data(), container.size() * sizeof(*container.data())); }
template<class T, size_t N>
inline HexDump hexdump(const T (&arr)[N]) { return HexDump(arr, N * sizeof(*arr)); }
}

View file

@ -0,0 +1,24 @@
#pragma once
#define PLOG_IMPL_PRINT_VAR_1(a1) #a1 ": " << a1
#define PLOG_IMPL_PRINT_VAR_2(a1, a2) PLOG_IMPL_PRINT_VAR_1(a1) PLOG_IMPL_PRINT_VAR_TAIL(a2)
#define PLOG_IMPL_PRINT_VAR_3(a1, a2, a3) PLOG_IMPL_PRINT_VAR_2(a1, a2) PLOG_IMPL_PRINT_VAR_TAIL(a3)
#define PLOG_IMPL_PRINT_VAR_4(a1, a2, a3, a4) PLOG_IMPL_PRINT_VAR_3(a1, a2, a3) PLOG_IMPL_PRINT_VAR_TAIL(a4)
#define PLOG_IMPL_PRINT_VAR_5(a1, a2, a3, a4, a5) PLOG_IMPL_PRINT_VAR_4(a1, a2, a3, a4) PLOG_IMPL_PRINT_VAR_TAIL(a5)
#define PLOG_IMPL_PRINT_VAR_6(a1, a2, a3, a4, a5, a6) PLOG_IMPL_PRINT_VAR_5(a1, a2, a3, a4, a5) PLOG_IMPL_PRINT_VAR_TAIL(a6)
#define PLOG_IMPL_PRINT_VAR_7(a1, a2, a3, a4, a5, a6, a7) PLOG_IMPL_PRINT_VAR_6(a1, a2, a3, a4, a5, a6) PLOG_IMPL_PRINT_VAR_TAIL(a7)
#define PLOG_IMPL_PRINT_VAR_8(a1, a2, a3, a4, a5, a6, a7, a8) PLOG_IMPL_PRINT_VAR_7(a1, a2, a3, a4, a5, a6, a7) PLOG_IMPL_PRINT_VAR_TAIL(a8)
#define PLOG_IMPL_PRINT_VAR_9(a1, a2, a3, a4, a5, a6, a7, a8, a9) PLOG_IMPL_PRINT_VAR_8(a1, a2, a3, a4, a5, a6, a7, a8) PLOG_IMPL_PRINT_VAR_TAIL(a9)
#define PLOG_IMPL_PRINT_VAR_TAIL(a) << ", " PLOG_IMPL_PRINT_VAR_1(a)
#define PLOG_IMPL_PRINT_VAR_EXPAND(x) x
#ifdef __GNUC__
#pragma GCC system_header // disable warning: variadic macros are a C99 feature
#endif
#define PLOG_IMPL_PRINT_VAR_GET_MACRO(x1, x2, x3, x4, x5, x6, x7, x8, x9, NAME, ...) NAME
#define PLOG_PRINT_VAR(...) PLOG_IMPL_PRINT_VAR_EXPAND(PLOG_IMPL_PRINT_VAR_GET_MACRO(__VA_ARGS__,\
PLOG_IMPL_PRINT_VAR_9, PLOG_IMPL_PRINT_VAR_8, PLOG_IMPL_PRINT_VAR_7, PLOG_IMPL_PRINT_VAR_6, PLOG_IMPL_PRINT_VAR_5,\
PLOG_IMPL_PRINT_VAR_4, PLOG_IMPL_PRINT_VAR_3, PLOG_IMPL_PRINT_VAR_2, PLOG_IMPL_PRINT_VAR_1, UNUSED)(__VA_ARGS__))

17
include/plog/Init.h Normal file
View file

@ -0,0 +1,17 @@
#pragma once
#include <plog/Logger.h>
namespace plog
{
template<int instanceId>
PLOG_LINKAGE_HIDDEN inline Logger<instanceId>& init(Severity maxSeverity = none, IAppender* appender = NULL)
{
static Logger<instanceId> logger(maxSeverity);
return appender ? logger.addAppender(appender) : logger;
}
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity = none, IAppender* appender = NULL)
{
return init<PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, appender);
}
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <plog/Appenders/ColorConsoleAppender.h>
#include <plog/Init.h>
namespace plog
{
//////////////////////////////////////////////////////////////////////////
// ColorConsoleAppender with any Formatter
template<class Formatter, int instanceId>
PLOG_LINKAGE_HIDDEN inline Logger<instanceId>& init(Severity maxSeverity, OutputStream outputStream)
{
static ColorConsoleAppender<Formatter> appender(outputStream);
return init<instanceId>(maxSeverity, &appender);
}
template<class Formatter>
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity, OutputStream outputStream)
{
return init<Formatter, PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, outputStream);
}
}

View file

@ -0,0 +1,80 @@
#pragma once
#include <plog/Appenders/RollingFileAppender.h>
#include <plog/Formatters/TxtFormatter.h>
#include <plog/Formatters/CsvFormatter.h>
#include <plog/Init.h>
#include <cstring>
namespace plog
{
//////////////////////////////////////////////////////////////////////////
// RollingFileAppender with any Formatter
template<class Formatter, int instanceId>
PLOG_LINKAGE_HIDDEN inline Logger<instanceId>& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
static RollingFileAppender<Formatter> rollingFileAppender(fileName, maxFileSize, maxFiles);
return init<instanceId>(maxSeverity, &rollingFileAppender);
}
template<class Formatter>
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<Formatter, PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, fileName, maxFileSize, maxFiles);
}
//////////////////////////////////////////////////////////////////////////
// RollingFileAppender with TXT/CSV chosen by file extension
namespace
{
inline bool isCsv(const util::nchar* fileName)
{
const util::nchar* dot = util::findExtensionDot(fileName);
#if PLOG_CHAR_IS_UTF8
return dot && 0 == std::strcmp(dot, ".csv");
#else
return dot && 0 == std::wcscmp(dot, L".csv");
#endif
}
}
template<int instanceId>
inline Logger<instanceId>& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return isCsv(fileName) ? init<CsvFormatter, instanceId>(maxSeverity, fileName, maxFileSize, maxFiles) : init<TxtFormatter, instanceId>(maxSeverity, fileName, maxFileSize, maxFiles);
}
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity, const util::nchar* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, fileName, maxFileSize, maxFiles);
}
//////////////////////////////////////////////////////////////////////////
// CHAR variants for Windows
#if defined(_WIN32) && !PLOG_CHAR_IS_UTF8
template<class Formatter, int instanceId>
inline Logger<instanceId>& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<Formatter, instanceId>(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles);
}
template<class Formatter>
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<Formatter, PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, fileName, maxFileSize, maxFiles);
}
template<int instanceId>
inline Logger<instanceId>& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<instanceId>(maxSeverity, util::toWide(fileName).c_str(), maxFileSize, maxFiles);
}
inline Logger<PLOG_DEFAULT_INSTANCE_ID>& init(Severity maxSeverity, const char* fileName, size_t maxFileSize = 0, int maxFiles = 0)
{
return init<PLOG_DEFAULT_INSTANCE_ID>(maxSeverity, fileName, maxFileSize, maxFiles);
}
#endif
}

202
include/plog/Log.h Normal file
View file

@ -0,0 +1,202 @@
//////////////////////////////////////////////////////////////////////////
// Plog - portable and simple log for C++
// Documentation and sources: https://github.com/SergiusTheBest/plog
// License: MIT, https://choosealicense.com/licenses/mit
#pragma once
#include <plog/Logger.h>
//////////////////////////////////////////////////////////////////////////
// Helper macros that get context info
#if defined(PLOG_ENABLE_GET_THIS) && defined(_MSC_VER) && _MSC_VER >= 1600 && !defined(__INTELLISENSE__) && !defined(__INTEL_COMPILER) && !defined(__llvm__) && !defined(__RESHARPER__) // >= Visual Studio 2010, skip IntelliSense, Intel Compiler, Clang Code Model and ReSharper
# define PLOG_GET_THIS() __if_exists(this) { this } __if_not_exists(this) { 0 }
#else
# define PLOG_GET_THIS() reinterpret_cast<void*>(0)
#endif
#ifdef _MSC_VER
# define PLOG_GET_FUNC() __FUNCTION__
#elif defined(__BORLANDC__)
# define PLOG_GET_FUNC() __FUNC__
#else
# define PLOG_GET_FUNC() __PRETTY_FUNCTION__
#endif
#ifdef PLOG_CAPTURE_FILE
# define PLOG_GET_FILE() __FILE__
#else
# define PLOG_GET_FILE() ""
#endif
//////////////////////////////////////////////////////////////////////////
// Log severity level checker
#ifdef PLOG_DISABLE_LOGGING
# ifdef _MSC_VER
# define IF_PLOG_(instanceId, severity) __pragma(warning(push)) __pragma(warning(disable:4127)) if (true) {;} else __pragma(warning(pop)) // conditional expression is constant
# else
# define IF_PLOG_(instanceId, severity) if (true) {;} else
# endif
#else
# define IF_PLOG_(instanceId, severity) if (!plog::get<instanceId>() || !plog::get<instanceId>()->checkSeverity(severity)) {;} else
#endif
#define IF_PLOG(severity) IF_PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity)
//////////////////////////////////////////////////////////////////////////
// Main logging macros
#define PLOG_(instanceId, severity) IF_PLOG_(instanceId, severity) (*plog::get<instanceId>()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS(), instanceId).ref()
#define PLOG(severity) PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity)
#define PLOG_VERBOSE PLOG(plog::verbose)
#define PLOG_DEBUG PLOG(plog::debug)
#define PLOG_INFO PLOG(plog::info)
#define PLOG_WARNING PLOG(plog::warning)
#define PLOG_ERROR PLOG(plog::error)
#define PLOG_FATAL PLOG(plog::fatal)
#define PLOG_NONE PLOG(plog::none)
#define PLOG_VERBOSE_(instanceId) PLOG_(instanceId, plog::verbose)
#define PLOG_DEBUG_(instanceId) PLOG_(instanceId, plog::debug)
#define PLOG_INFO_(instanceId) PLOG_(instanceId, plog::info)
#define PLOG_WARNING_(instanceId) PLOG_(instanceId, plog::warning)
#define PLOG_ERROR_(instanceId) PLOG_(instanceId, plog::error)
#define PLOG_FATAL_(instanceId) PLOG_(instanceId, plog::fatal)
#define PLOG_NONE_(instanceId) PLOG_(instanceId, plog::none)
#define PLOGV PLOG_VERBOSE
#define PLOGD PLOG_DEBUG
#define PLOGI PLOG_INFO
#define PLOGW PLOG_WARNING
#define PLOGE PLOG_ERROR
#define PLOGF PLOG_FATAL
#define PLOGN PLOG_NONE
#define PLOGV_(instanceId) PLOG_VERBOSE_(instanceId)
#define PLOGD_(instanceId) PLOG_DEBUG_(instanceId)
#define PLOGI_(instanceId) PLOG_INFO_(instanceId)
#define PLOGW_(instanceId) PLOG_WARNING_(instanceId)
#define PLOGE_(instanceId) PLOG_ERROR_(instanceId)
#define PLOGF_(instanceId) PLOG_FATAL_(instanceId)
#define PLOGN_(instanceId) PLOG_NONE_(instanceId)
//////////////////////////////////////////////////////////////////////////
// Conditional logging macros
#define PLOG_IF_(instanceId, severity, condition) if (!(condition)) {;} else PLOG_(instanceId, severity)
#define PLOG_IF(severity, condition) PLOG_IF_(PLOG_DEFAULT_INSTANCE_ID, severity, condition)
#define PLOG_VERBOSE_IF(condition) PLOG_IF(plog::verbose, condition)
#define PLOG_DEBUG_IF(condition) PLOG_IF(plog::debug, condition)
#define PLOG_INFO_IF(condition) PLOG_IF(plog::info, condition)
#define PLOG_WARNING_IF(condition) PLOG_IF(plog::warning, condition)
#define PLOG_ERROR_IF(condition) PLOG_IF(plog::error, condition)
#define PLOG_FATAL_IF(condition) PLOG_IF(plog::fatal, condition)
#define PLOG_NONE_IF(condition) PLOG_IF(plog::none, condition)
#define PLOG_VERBOSE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::verbose, condition)
#define PLOG_DEBUG_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::debug, condition)
#define PLOG_INFO_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::info, condition)
#define PLOG_WARNING_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::warning, condition)
#define PLOG_ERROR_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::error, condition)
#define PLOG_FATAL_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::fatal, condition)
#define PLOG_NONE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::none, condition)
#define PLOGV_IF(condition) PLOG_VERBOSE_IF(condition)
#define PLOGD_IF(condition) PLOG_DEBUG_IF(condition)
#define PLOGI_IF(condition) PLOG_INFO_IF(condition)
#define PLOGW_IF(condition) PLOG_WARNING_IF(condition)
#define PLOGE_IF(condition) PLOG_ERROR_IF(condition)
#define PLOGF_IF(condition) PLOG_FATAL_IF(condition)
#define PLOGN_IF(condition) PLOG_NONE_IF(condition)
#define PLOGV_IF_(instanceId, condition) PLOG_VERBOSE_IF_(instanceId, condition)
#define PLOGD_IF_(instanceId, condition) PLOG_DEBUG_IF_(instanceId, condition)
#define PLOGI_IF_(instanceId, condition) PLOG_INFO_IF_(instanceId, condition)
#define PLOGW_IF_(instanceId, condition) PLOG_WARNING_IF_(instanceId, condition)
#define PLOGE_IF_(instanceId, condition) PLOG_ERROR_IF_(instanceId, condition)
#define PLOGF_IF_(instanceId, condition) PLOG_FATAL_IF_(instanceId, condition)
#define PLOGN_IF_(instanceId, condition) PLOG_NONE_IF_(instanceId, condition)
// Old macro names for downward compatibility. To bypass including these macro names, add
// #define PLOG_OMIT_LOG_DEFINES before #include <plog/Log.h>
#ifndef PLOG_OMIT_LOG_DEFINES
//////////////////////////////////////////////////////////////////////////
// Main logging macros - can be changed later to point at macros for a different logging package
#define LOG_(instanceId, severity) IF_PLOG_(instanceId, severity) (*plog::get<instanceId>()) += plog::Record(severity, PLOG_GET_FUNC(), __LINE__, PLOG_GET_FILE(), PLOG_GET_THIS(), instanceId).ref()
#define LOG(severity) PLOG_(PLOG_DEFAULT_INSTANCE_ID, severity)
#define LOG_VERBOSE PLOG(plog::verbose)
#define LOG_DEBUG PLOG(plog::debug)
#define LOG_INFO PLOG(plog::info)
#define LOG_WARNING PLOG(plog::warning)
#define LOG_ERROR PLOG(plog::error)
#define LOG_FATAL PLOG(plog::fatal)
#define LOG_NONE PLOG(plog::none)
#define LOG_VERBOSE_(instanceId) PLOG_(instanceId, plog::verbose)
#define LOG_DEBUG_(instanceId) PLOG_(instanceId, plog::debug)
#define LOG_INFO_(instanceId) PLOG_(instanceId, plog::info)
#define LOG_WARNING_(instanceId) PLOG_(instanceId, plog::warning)
#define LOG_ERROR_(instanceId) PLOG_(instanceId, plog::error)
#define LOG_FATAL_(instanceId) PLOG_(instanceId, plog::fatal)
#define LOG_NONE_(instanceId) PLOG_(instanceId, plog::none)
#define LOGV PLOG_VERBOSE
#define LOGD PLOG_DEBUG
#define LOGI PLOG_INFO
#define LOGW PLOG_WARNING
#define LOGE PLOG_ERROR
#define LOGF PLOG_FATAL
#define LOGN PLOG_NONE
#define LOGV_(instanceId) PLOG_VERBOSE_(instanceId)
#define LOGD_(instanceId) PLOG_DEBUG_(instanceId)
#define LOGI_(instanceId) PLOG_INFO_(instanceId)
#define LOGW_(instanceId) PLOG_WARNING_(instanceId)
#define LOGE_(instanceId) PLOG_ERROR_(instanceId)
#define LOGF_(instanceId) PLOG_FATAL_(instanceId)
#define LOGN_(instanceId) PLOG_NONE_(instanceId)
//////////////////////////////////////////////////////////////////////////
// Conditional logging macros
#define LOG_IF_(instanceId, severity, condition) if (!(condition)) {;} else PLOG_(instanceId, severity)
#define LOG_IF(severity, condition) PLOG_IF_(PLOG_DEFAULT_INSTANCE_ID, severity, condition)
#define LOG_VERBOSE_IF(condition) PLOG_IF(plog::verbose, condition)
#define LOG_DEBUG_IF(condition) PLOG_IF(plog::debug, condition)
#define LOG_INFO_IF(condition) PLOG_IF(plog::info, condition)
#define LOG_WARNING_IF(condition) PLOG_IF(plog::warning, condition)
#define LOG_ERROR_IF(condition) PLOG_IF(plog::error, condition)
#define LOG_FATAL_IF(condition) PLOG_IF(plog::fatal, condition)
#define LOG_NONE_IF(condition) PLOG_IF(plog::none, condition)
#define LOG_VERBOSE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::verbose, condition)
#define LOG_DEBUG_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::debug, condition)
#define LOG_INFO_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::info, condition)
#define LOG_WARNING_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::warning, condition)
#define LOG_ERROR_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::error, condition)
#define LOG_FATAL_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::fatal, condition)
#define LOG_NONE_IF_(instanceId, condition) PLOG_IF_(instanceId, plog::none, condition)
#define LOGV_IF(condition) PLOG_VERBOSE_IF(condition)
#define LOGD_IF(condition) PLOG_DEBUG_IF(condition)
#define LOGI_IF(condition) PLOG_INFO_IF(condition)
#define LOGW_IF(condition) PLOG_WARNING_IF(condition)
#define LOGE_IF(condition) PLOG_ERROR_IF(condition)
#define LOGF_IF(condition) PLOG_FATAL_IF(condition)
#define LOGN_IF(condition) PLOG_NONE_IF(condition)
#define LOGV_IF_(instanceId, condition) PLOG_VERBOSE_IF_(instanceId, condition)
#define LOGD_IF_(instanceId, condition) PLOG_DEBUG_IF_(instanceId, condition)
#define LOGI_IF_(instanceId, condition) PLOG_INFO_IF_(instanceId, condition)
#define LOGW_IF_(instanceId, condition) PLOG_WARNING_IF_(instanceId, condition)
#define LOGE_IF_(instanceId, condition) PLOG_ERROR_IF_(instanceId, condition)
#define LOGF_IF_(instanceId, condition) PLOG_FATAL_IF_(instanceId, condition)
#define LOGN_IF_(instanceId, condition) PLOG_NONE_IF_(instanceId, condition)
#endif

84
include/plog/Logger.h Normal file
View file

@ -0,0 +1,84 @@
#pragma once
#include <plog/Appenders/IAppender.h>
#include <plog/Util.h>
#include <vector>
#ifdef PLOG_DEFAULT_INSTANCE // for backward compatibility
# define PLOG_DEFAULT_INSTANCE_ID PLOG_DEFAULT_INSTANCE
#endif
#ifndef PLOG_DEFAULT_INSTANCE_ID
# define PLOG_DEFAULT_INSTANCE_ID 0
#endif
namespace plog
{
template<int instanceId>
class PLOG_LINKAGE Logger : public util::Singleton<Logger<instanceId> >, public IAppender
{
public:
Logger(Severity maxSeverity = none) : m_maxSeverity(maxSeverity)
{
}
Logger& addAppender(IAppender* appender)
{
assert(appender != this);
m_appenders.push_back(appender);
return *this;
}
Severity getMaxSeverity() const
{
return m_maxSeverity;
}
void setMaxSeverity(Severity severity)
{
m_maxSeverity = severity;
}
bool checkSeverity(Severity severity) const
{
return severity <= m_maxSeverity;
}
virtual void write(const Record& record) PLOG_OVERRIDE
{
if (checkSeverity(record.getSeverity()))
{
*this += record;
}
}
void operator+=(const Record& record)
{
for (std::vector<IAppender*>::iterator it = m_appenders.begin(); it != m_appenders.end(); ++it)
{
(*it)->write(record);
}
}
private:
Severity m_maxSeverity;
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4251) // needs to have dll-interface to be used by clients of class
#endif
std::vector<IAppender*> m_appenders;
#ifdef _MSC_VER
# pragma warning(pop)
#endif
};
template<int instanceId>
inline Logger<instanceId>* get()
{
return Logger<instanceId>::getInstance();
}
inline Logger<PLOG_DEFAULT_INSTANCE_ID>* get()
{
return Logger<PLOG_DEFAULT_INSTANCE_ID>::getInstance();
}
}

465
include/plog/Record.h Normal file
View file

@ -0,0 +1,465 @@
#pragma once
#include <cstdarg>
#include <plog/Severity.h>
#include <plog/Util.h>
#ifdef __cplusplus_cli
#include <vcclr.h> // For PtrToStringChars
#endif
namespace plog
{
namespace detail
{
#if !defined(_MSC_VER) || _MSC_VER > 1400 // MSVC 2005 doesn't understand `enableIf`, so drop all `meta`
namespace meta
{
template<class T>
inline T& declval()
{
#ifdef __INTEL_COMPILER
# pragma warning(suppress: 327) // NULL reference is not allowed
#endif
return *reinterpret_cast<T*>(0);
}
template<bool B, class T = void>
struct enableIf {};
template<class T>
struct enableIf<true, T> { typedef T type; };
struct No { char a[1]; };
struct Yes { char a[2]; };
template <class From, class To>
struct isConvertible
{
// `+ sizeof(U*)` is required for GCC 4.5-4.7
template<class U>
static typename enableIf<!!(sizeof(static_cast<To>(meta::declval<U>())) + sizeof(U*)), Yes>::type test(int);
template<class U>
static No test(...);
enum { value = sizeof(test<From>(0)) == sizeof(Yes) };
};
template <class T>
struct isConvertibleToString : isConvertible<T, std::string> {};
#if PLOG_ENABLE_WCHAR_INPUT
template <class T>
struct isConvertibleToWString : isConvertible<T, std::wstring> {};
#endif
template <class T>
struct isContainer
{
template<class U>
static typename meta::enableIf<!!(sizeof(
#if defined(_MSC_VER) && _MSC_VER < 1700 // MSVC 2010 doesn't understand `typename T::const_iterator`
meta::declval<U>().begin()) + sizeof(meta::declval<U>().end()
#else
typename U::const_iterator
#endif
)), Yes>::type test(int);
template<class U>
static No test(...);
enum { value = sizeof(test<T>(0)) == sizeof(Yes) };
};
// Detects `std::filesystem::path` and `boost::filesystem::path`. They look like containers
// but we don't want to treat them as containers, so we use this detector to filter them out.
template <class T>
struct isFilesystemPath
{
template<class U>
static typename meta::enableIf<!!(sizeof(meta::declval<U>().preferred_separator)), Yes>::type test(int);
template<class U>
static No test(...);
enum { value = sizeof(test<T>(0)) == sizeof(Yes) };
};
}
#endif
//////////////////////////////////////////////////////////////////////////
// Stream output operators as free functions
#if PLOG_ENABLE_WCHAR_INPUT
inline void operator<<(util::nostringstream& stream, const wchar_t* data)
{
data = data ? data : L"(null)";
# ifdef _WIN32
# if PLOG_CHAR_IS_UTF8
std::operator<<(stream, util::toNarrow(data, codePage::kUTF8));
# else
std::operator<<(stream, data);
# endif
# else
std::operator<<(stream, util::toNarrow(data));
# endif
}
inline void operator<<(util::nostringstream& stream, wchar_t* data)
{
plog::detail::operator<<(stream, const_cast<const wchar_t*>(data));
}
inline void operator<<(util::nostringstream& stream, const std::wstring& data)
{
plog::detail::operator<<(stream, data.c_str());
}
#endif
inline void operator<<(util::nostringstream& stream, const char* data)
{
data = data ? data : "(null)";
#if defined(_WIN32) && defined(__BORLANDC__)
# if PLOG_CHAR_IS_UTF8
stream << data;
# else
stream << util::toWide(data);
# endif
#elif defined(_WIN32)
# if PLOG_CHAR_IS_UTF8
std::operator<<(stream, data);
# else
std::operator<<(stream, util::toWide(data));
# endif
#else
std::operator<<(stream, data);
#endif
}
inline void operator<<(util::nostringstream& stream, char* data)
{
plog::detail::operator<<(stream, const_cast<const char*>(data));
}
inline void operator<<(util::nostringstream& stream, const std::string& data)
{
plog::detail::operator<<(stream, data.c_str());
}
#ifdef __cpp_char8_t
inline void operator<<(util::nostringstream& stream, const char8_t* data)
{
# if PLOG_CHAR_IS_UTF8
plog::detail::operator<<(stream, reinterpret_cast<const char*>(data));
# else
plog::detail::operator<<(stream, util::toWide(reinterpret_cast<const char*>(data), codePage::kUTF8));
# endif
}
#endif //__cpp_char8_t
// Print `std::pair`
template<class T1, class T2>
inline void operator<<(util::nostringstream& stream, const std::pair<T1, T2>& data)
{
stream << data.first;
stream << ":";
stream << data.second;
}
#if defined(__clang__) || !defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 // skip for GCC < 4.5 due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38600
#if !defined(_MSC_VER) || _MSC_VER > 1400 // MSVC 2005 doesn't understand `enableIf`, so drop all `meta`
// Print data that can be casted to `std::string`
template<class T>
inline typename meta::enableIf<meta::isConvertibleToString<T>::value, void>::type operator<<(util::nostringstream& stream, const T& data)
{
plog::detail::operator<<(stream, static_cast<std::string>(data));
}
#if PLOG_ENABLE_WCHAR_INPUT
// Print data that can be casted to `std::wstring`
template<class T>
inline typename meta::enableIf<meta::isConvertibleToWString<T>::value, void>::type operator<<(util::nostringstream& stream, const T& data)
{
plog::detail::operator<<(stream, static_cast<std::wstring>(data));
}
#endif
// Print std containers
template<class T>
inline typename meta::enableIf<meta::isContainer<T>::value &&
!meta::isConvertibleToString<T>::value &&
#if PLOG_ENABLE_WCHAR_INPUT
!meta::isConvertibleToWString<T>::value &&
#endif
!meta::isFilesystemPath<T>::value, void>::type operator<<(util::nostringstream& stream, const T& data)
{
stream << "[";
for (typename T::const_iterator it = data.begin(); it != data.end();)
{
stream << *it;
if (++it == data.end())
{
break;
}
stream << ", ";
}
stream << "]";
}
#endif
#endif
#ifdef __cplusplus_cli
// Print managed C++ `System::String^`
inline void operator<<(util::nostringstream& stream, System::String^ data)
{
cli::pin_ptr<const System::Char> ptr = PtrToStringChars(data);
plog::detail::operator<<(stream, static_cast<const wchar_t*>(ptr));
}
#endif
#if PLOG_ENABLE_WCHAR_INPUT && (!defined(_MSC_VER) || _MSC_VER > 1400) // MSVC 2005 doesn't understand `enableIf`, so drop all `meta`
namespace meta
{
template<bool Value>
struct valueType { enum { value = Value }; };
template<class T, class Stream>
inline No operator<<(Stream&, const T&);
template<class T, class Stream>
struct isStreamable : valueType<sizeof(operator<<(meta::declval<Stream>(), meta::declval<const T>())) != sizeof(No)> {};
template<class Stream>
struct isStreamable<std::ios_base& PLOG_CDECL (std::ios_base&), Stream> : valueType<true> {};
template<class Stream, size_t N>
struct isStreamable<wchar_t[N], Stream> : valueType<false> {};
template<class Stream, size_t N>
struct isStreamable<const wchar_t[N], Stream> : valueType<false> {};
// meta doesn't work well for deleted functions and C++20 has `operator<<(std::ostream&, const wchar_t*) = delete` so exlicitly define it
template<>
struct isStreamable<const wchar_t*, std::ostream> : valueType<false> {};
# ifdef __cpp_char8_t
// meta doesn't work well for deleted functions and C++20 has `operator<<(std::ostream&, const char8_t*) = delete` so exlicitly define it
template<class Stream, size_t N>
struct isStreamable<char8_t[N], Stream> : valueType<false> {};
template<class Stream>
struct isStreamable<const char8_t*, Stream> : valueType<false> {};
# endif //__cpp_char8_t
}
# if PLOG_CHAR_IS_UTF8
// Print types that can be streamed into `std::owstringstream` but not into `std::ostringstream` when we use UTF-8 on Windows
template<class T>
inline typename meta::enableIf<meta::isStreamable<T, std::wostream>::value &&
!meta::isStreamable<T, std::ostream>::value &&
!meta::isConvertibleToWString<T>::value, void>::type operator<<(std::ostringstream& stream, const T& data)
{
std::wostringstream ss;
ss << data;
stream << ss.str();
}
# else
// Print types that can be streamed into `std::ostringstream` but not into `std::owstringstream` when we use `wchar_t` on Windows
template<class T>
inline typename meta::enableIf<meta::isStreamable<T, std::ostream>::value &&
!meta::isStreamable<T, std::wostream>::value &&
!meta::isConvertibleToString<T>::value, void>::type operator<<(std::wostringstream& stream, const T& data)
{
std::ostringstream ss;
ss << data;
stream << ss.str();
}
# endif
#endif
}
class Record
{
public:
Record(Severity severity, const char* func, size_t line, const char* file, const void* object, int instanceId)
: m_severity(severity), m_tid(util::gettid()), m_object(object), m_line(line), m_func(func), m_file(file), m_instanceId(instanceId)
{
util::ftime(&m_time);
}
Record& ref()
{
return *this;
}
//////////////////////////////////////////////////////////////////////////
// Stream output operators
Record& operator<<(char data)
{
char str[] = { data, 0 };
return *this << str;
}
#if PLOG_ENABLE_WCHAR_INPUT
Record& operator<<(wchar_t data)
{
wchar_t str[] = { data, 0 };
return *this << str;
}
#endif
Record& operator<<(util::nostream& (PLOG_CDECL *data)(util::nostream&))
{
m_message << data;
return *this;
}
#ifdef QT_VERSION
Record& operator<<(const QString& data)
{
# if PLOG_CHAR_IS_UTF8
return *this << data.toStdString();
# else
return *this << data.toStdWString();
# endif
}
# if QT_VERSION < 0x060000
Record& operator<<(const QStringRef& data)
{
return *this << data.toString();
}
# endif
# ifdef QSTRINGVIEW_H
Record& operator<<(QStringView data)
{
return *this << data.toString();
}
# endif
#endif
template<typename T>
Record& operator<<(const T& data)
{
using namespace plog::detail;
m_message << data;
return *this;
}
#ifndef __cplusplus_cli
Record& printf(const char* format, ...)
{
using namespace util;
char* str = NULL;
va_list ap;
va_start(ap, format);
int len = vasprintf(&str, format, ap);
static_cast<void>(len);
va_end(ap);
*this << str;
free(str);
return *this;
}
#ifdef _WIN32
Record& printf(const wchar_t* format, ...)
{
using namespace util;
wchar_t* str = NULL;
va_list ap;
va_start(ap, format);
int len = vaswprintf(&str, format, ap);
static_cast<void>(len);
va_end(ap);
*this << str;
free(str);
return *this;
}
#endif
#endif //__cplusplus_cli
//////////////////////////////////////////////////////////////////////////
// Getters
virtual const util::Time& getTime() const
{
return m_time;
}
virtual Severity getSeverity() const
{
return m_severity;
}
virtual unsigned int getTid() const
{
return m_tid;
}
virtual const void* getObject() const
{
return m_object;
}
virtual size_t getLine() const
{
return m_line;
}
virtual const util::nchar* getMessage() const
{
m_messageStr = m_message.str();
return m_messageStr.c_str();
}
virtual const char* getFunc() const
{
m_funcStr = util::processFuncName(m_func);
return m_funcStr.c_str();
}
virtual const char* getFile() const
{
return m_file;
}
virtual ~Record() // virtual destructor to satisfy -Wnon-virtual-dtor warning
{
}
virtual int getInstanceId() const
{
return m_instanceId;
}
private:
util::Time m_time;
const Severity m_severity;
const unsigned int m_tid;
const void* const m_object;
const size_t m_line;
util::nostringstream m_message;
const char* const m_func;
const char* const m_file;
const int m_instanceId;
mutable std::string m_funcStr;
mutable util::nstring m_messageStr;
};
}

61
include/plog/Severity.h Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include <cctype>
namespace plog
{
enum Severity
{
none = 0,
fatal = 1,
error = 2,
warning = 3,
info = 4,
debug = 5,
verbose = 6
};
#ifdef _MSC_VER
# pragma warning(suppress: 26812) // Prefer 'enum class' over 'enum'
#endif
inline const char* severityToString(Severity severity)
{
switch (severity)
{
case fatal:
return "FATAL";
case error:
return "ERROR";
case warning:
return "WARN";
case info:
return "INFO";
case debug:
return "DEBUG";
case verbose:
return "VERB";
default:
return "NONE";
}
}
inline Severity severityFromString(const char* str)
{
switch (std::toupper(str[0]))
{
case 'F':
return fatal;
case 'E':
return error;
case 'W':
return warning;
case 'I':
return info;
case 'D':
return debug;
case 'V':
return verbose;
default:
return none;
}
}
}

616
include/plog/Util.h Normal file
View file

@ -0,0 +1,616 @@
#pragma once
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef PLOG_ENABLE_WCHAR_INPUT
# ifdef _WIN32
# define PLOG_ENABLE_WCHAR_INPUT 1
# else
# define PLOG_ENABLE_WCHAR_INPUT 0
# endif
#endif
//////////////////////////////////////////////////////////////////////////
// PLOG_CHAR_IS_UTF8 specifies character encoding of `char` type. On *nix
// systems it's set to UTF-8 while on Windows in can be ANSI or UTF-8. It
// automatically detects `/utf-8` command line option in MSVC. Also it can
// be set manually if required.
// This option allows to support http://utf8everywhere.org approach.
#ifndef PLOG_CHAR_IS_UTF8
# if defined(_WIN32) && !defined(_UTF8)
# define PLOG_CHAR_IS_UTF8 0
# else
# define PLOG_CHAR_IS_UTF8 1
# endif
#endif
#ifdef _WIN32
# if defined(PLOG_EXPORT)
# define PLOG_LINKAGE __declspec(dllexport)
# elif defined(PLOG_IMPORT)
# define PLOG_LINKAGE __declspec(dllimport)
# endif
# if defined(PLOG_GLOBAL)
# error "PLOG_GLOBAL isn't supported on Windows"
# endif
#else
# if defined(PLOG_GLOBAL)
# define PLOG_LINKAGE __attribute__ ((visibility ("default")))
# elif defined(PLOG_LOCAL)
# define PLOG_LINKAGE __attribute__ ((visibility ("hidden")))
# define PLOG_LINKAGE_HIDDEN PLOG_LINKAGE
# endif
# if defined(PLOG_EXPORT) || defined(PLOG_IMPORT)
# error "PLOG_EXPORT/PLOG_IMPORT is supported only on Windows"
# endif
#endif
#ifndef PLOG_LINKAGE
# define PLOG_LINKAGE
#endif
#ifndef PLOG_LINKAGE_HIDDEN
# define PLOG_LINKAGE_HIDDEN
#endif
#ifdef _WIN32
# include <plog/WinApi.h>
# include <time.h>
# include <sys/timeb.h>
# include <io.h>
# include <share.h>
#else
# include <unistd.h>
# include <sys/time.h>
# if defined(__linux__) || defined(__FreeBSD__)
# include <sys/syscall.h>
# elif defined(__rtems__)
# include <rtems.h>
# endif
# if defined(_POSIX_THREADS)
# include <pthread.h>
# endif
# if PLOG_ENABLE_WCHAR_INPUT
# include <iconv.h>
# endif
#endif
#if PLOG_CHAR_IS_UTF8
# define PLOG_NSTR(x) x
#else
# define _PLOG_NSTR(x) L##x
# define PLOG_NSTR(x) _PLOG_NSTR(x)
#endif
#ifdef _WIN32
# define PLOG_CDECL __cdecl
#else
# define PLOG_CDECL
#endif
#if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1700
# define PLOG_OVERRIDE override
#else
# define PLOG_OVERRIDE
#endif
namespace plog
{
namespace util
{
#if PLOG_CHAR_IS_UTF8
typedef std::string nstring;
typedef std::ostringstream nostringstream;
typedef std::istringstream nistringstream;
typedef std::ostream nostream;
typedef char nchar;
#else
typedef std::wstring nstring;
typedef std::wostringstream nostringstream;
typedef std::wistringstream nistringstream;
typedef std::wostream nostream;
typedef wchar_t nchar;
#endif
inline void localtime_s(struct tm* t, const time_t* time)
{
#if defined(_WIN32) && defined(__BORLANDC__)
::localtime_s(time, t);
#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
*t = *::localtime(time);
#elif defined(_WIN32)
::localtime_s(t, time);
#else
::localtime_r(time, t);
#endif
}
inline void gmtime_s(struct tm* t, const time_t* time)
{
#if defined(_WIN32) && defined(__BORLANDC__)
::gmtime_s(time, t);
#elif defined(_WIN32) && defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
*t = *::gmtime(time);
#elif defined(_WIN32)
::gmtime_s(t, time);
#else
::gmtime_r(time, t);
#endif
}
#ifdef _WIN32
typedef timeb Time;
inline void ftime(Time* t)
{
::ftime(t);
}
#else
struct Time
{
time_t time;
unsigned short millitm;
};
inline void ftime(Time* t)
{
timeval tv;
::gettimeofday(&tv, NULL);
t->time = tv.tv_sec;
t->millitm = static_cast<unsigned short>(tv.tv_usec / 1000);
}
#endif
inline unsigned int gettid()
{
#ifdef _WIN32
return GetCurrentThreadId();
#elif defined(__linux__)
return static_cast<unsigned int>(::syscall(__NR_gettid));
#elif defined(__FreeBSD__)
long tid;
syscall(SYS_thr_self, &tid);
return static_cast<unsigned int>(tid);
#elif defined(__rtems__)
return rtems_task_self();
#elif defined(__APPLE__)
uint64_t tid64;
pthread_threadid_np(NULL, &tid64);
return static_cast<unsigned int>(tid64);
#else
return 0;
#endif
}
#ifndef _GNU_SOURCE
inline int vasprintf(char** strp, const char* format, va_list ap)
{
va_list ap_copy;
#if defined(_MSC_VER) && _MSC_VER <= 1600
ap_copy = ap; // there is no va_copy on Visual Studio 2010
#else
va_copy(ap_copy, ap);
#endif
#ifndef __STDC_SECURE_LIB__
int charCount = vsnprintf(NULL, 0, format, ap_copy);
#else
int charCount = _vscprintf(format, ap_copy);
#endif
va_end(ap_copy);
if (charCount < 0)
{
return -1;
}
size_t bufferCharCount = static_cast<size_t>(charCount) + 1;
char* str = static_cast<char*>(malloc(bufferCharCount));
if (!str)
{
return -1;
}
#ifndef __STDC_SECURE_LIB__
int retval = vsnprintf(str, bufferCharCount, format, ap);
#else
int retval = vsnprintf_s(str, bufferCharCount, static_cast<size_t>(-1), format, ap);
#endif
if (retval < 0)
{
free(str);
return -1;
}
*strp = str;
return retval;
}
#endif
#ifdef _WIN32
inline int vaswprintf(wchar_t** strp, const wchar_t* format, va_list ap)
{
#if defined(__BORLANDC__)
int charCount = 0x1000; // there is no _vscwprintf on Borland/Embarcadero
#else
int charCount = _vscwprintf(format, ap);
if (charCount < 0)
{
return -1;
}
#endif
size_t bufferCharCount = static_cast<size_t>(charCount) + 1;
wchar_t* str = static_cast<wchar_t*>(malloc(bufferCharCount * sizeof(wchar_t)));
if (!str)
{
return -1;
}
#if defined(__BORLANDC__)
int retval = vsnwprintf_s(str, bufferCharCount, format, ap);
#elif defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
int retval = _vsnwprintf(str, bufferCharCount, format, ap);
#else
int retval = _vsnwprintf_s(str, bufferCharCount, charCount, format, ap);
#endif
if (retval < 0)
{
free(str);
return -1;
}
*strp = str;
return retval;
}
#endif
#ifdef _WIN32
inline std::wstring toWide(const char* str, UINT cp = codePage::kChar)
{
size_t len = ::strlen(str);
std::wstring wstr(len, 0);
if (!wstr.empty())
{
int wlen = MultiByteToWideChar(cp, 0, str, static_cast<int>(len), &wstr[0], static_cast<int>(wstr.size()));
wstr.resize(wlen);
}
return wstr;
}
inline std::wstring toWide(const std::string& str, UINT cp = codePage::kChar)
{
return toWide(str.c_str(), cp);
}
inline const std::wstring& toWide(const std::wstring& str) // do nothing for already wide string
{
return str;
}
inline std::string toNarrow(const std::wstring& wstr, long page)
{
int len = WideCharToMultiByte(page, 0, wstr.c_str(), static_cast<int>(wstr.size()), 0, 0, 0, 0);
std::string str(len, 0);
if (!str.empty())
{
WideCharToMultiByte(page, 0, wstr.c_str(), static_cast<int>(wstr.size()), &str[0], len, 0, 0);
}
return str;
}
#elif PLOG_ENABLE_WCHAR_INPUT
inline std::string toNarrow(const wchar_t* wstr)
{
size_t wlen = ::wcslen(wstr);
std::string str(wlen * sizeof(wchar_t), 0);
if (!str.empty())
{
const char* in = reinterpret_cast<const char*>(&wstr[0]);
char* out = &str[0];
size_t inBytes = wlen * sizeof(wchar_t);
size_t outBytes = str.size();
iconv_t cd = ::iconv_open("UTF-8", "WCHAR_T");
::iconv(cd, const_cast<char**>(&in), &inBytes, &out, &outBytes);
::iconv_close(cd);
str.resize(str.size() - outBytes);
}
return str;
}
#endif
inline std::string processFuncName(const char* func)
{
#if (defined(_WIN32) && !defined(__MINGW32__)) || defined(__OBJC__)
return std::string(func);
#else
const char* funcBegin = func;
const char* funcEnd = ::strchr(funcBegin, '(');
int foundTemplate = 0;
if (!funcEnd)
{
return std::string(func);
}
for (const char* i = funcEnd - 1; i >= funcBegin; --i) // search backwards for the first space char
{
if (*i == '>')
{
foundTemplate++;
}
else if (*i == '<')
{
foundTemplate--;
}
else if (*i == ' ' && foundTemplate == 0)
{
funcBegin = i + 1;
break;
}
}
return std::string(funcBegin, funcEnd);
#endif
}
inline const nchar* findExtensionDot(const nchar* fileName)
{
#if PLOG_CHAR_IS_UTF8
return std::strrchr(fileName, '.');
#else
return std::wcsrchr(fileName, L'.');
#endif
}
inline void splitFileName(const nchar* fileName, nstring& fileNameNoExt, nstring& fileExt)
{
const nchar* dot = findExtensionDot(fileName);
if (dot)
{
fileNameNoExt.assign(fileName, dot);
fileExt.assign(dot + 1);
}
else
{
fileNameNoExt.assign(fileName);
fileExt.clear();
}
}
class PLOG_LINKAGE NonCopyable
{
protected:
NonCopyable()
{
}
private:
NonCopyable(const NonCopyable&);
NonCopyable& operator=(const NonCopyable&);
};
class PLOG_LINKAGE_HIDDEN File : NonCopyable
{
public:
File() : m_file(-1)
{
}
~File()
{
close();
}
size_t open(const nstring& fileName)
{
#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__))
m_file = ::_wsopen(toWide(fileName).c_str(), _O_CREAT | _O_WRONLY | _O_BINARY | _O_NOINHERIT, SH_DENYWR, _S_IREAD | _S_IWRITE);
#elif defined(_WIN32)
::_wsopen_s(&m_file, toWide(fileName).c_str(), _O_CREAT | _O_WRONLY | _O_BINARY | _O_NOINHERIT, _SH_DENYWR, _S_IREAD | _S_IWRITE);
#elif defined(O_CLOEXEC)
m_file = ::open(fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#else
m_file = ::open(fileName.c_str(), O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
return seek(0, SEEK_END);
}
size_t write(const void* buf, size_t count)
{
return m_file != -1 ? static_cast<size_t>(
#ifdef _WIN32
::_write(m_file, buf, static_cast<unsigned int>(count))
#else
::write(m_file, buf, count)
#endif
) : static_cast<size_t>(-1);
}
template<class CharType>
size_t write(const std::basic_string<CharType>& str)
{
return write(str.data(), str.size() * sizeof(CharType));
}
size_t seek(size_t offset, int whence)
{
return m_file != -1 ? static_cast<size_t>(
#if defined(_WIN32) && (defined(__BORLANDC__) || defined(__MINGW32__))
::_lseek(m_file, static_cast<off_t>(offset), whence)
#elif defined(_WIN32)
::_lseeki64(m_file, static_cast<off_t>(offset), whence)
#else
::lseek(m_file, static_cast<off_t>(offset), whence)
#endif
) : static_cast<size_t>(-1);
}
void close()
{
if (m_file != -1)
{
#ifdef _WIN32
::_close(m_file);
#else
::close(m_file);
#endif
m_file = -1;
}
}
static int unlink(const nstring& fileName)
{
#ifdef _WIN32
return ::_wunlink(toWide(fileName).c_str());
#else
return ::unlink(fileName.c_str());
#endif
}
static int rename(const nstring& oldFilename, const nstring& newFilename)
{
#ifdef _WIN32
return MoveFileW(toWide(oldFilename).c_str(), toWide(newFilename).c_str());
#else
return ::rename(oldFilename.c_str(), newFilename.c_str());
#endif
}
private:
int m_file;
};
class PLOG_LINKAGE_HIDDEN Mutex : NonCopyable
{
public:
Mutex()
{
#ifdef _WIN32
InitializeCriticalSection(&m_sync);
#elif defined(__rtems__)
rtems_semaphore_create(0, 1,
RTEMS_PRIORITY |
RTEMS_BINARY_SEMAPHORE |
RTEMS_INHERIT_PRIORITY, 1, &m_sync);
#elif defined(_POSIX_THREADS)
::pthread_mutex_init(&m_sync, 0);
#endif
}
~Mutex()
{
#ifdef _WIN32
DeleteCriticalSection(&m_sync);
#elif defined(__rtems__)
rtems_semaphore_delete(m_sync);
#elif defined(_POSIX_THREADS)
::pthread_mutex_destroy(&m_sync);
#endif
}
friend class MutexLock;
private:
void lock()
{
#ifdef _WIN32
EnterCriticalSection(&m_sync);
#elif defined(__rtems__)
rtems_semaphore_obtain(m_sync, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
#elif defined(_POSIX_THREADS)
::pthread_mutex_lock(&m_sync);
#endif
}
void unlock()
{
#ifdef _WIN32
LeaveCriticalSection(&m_sync);
#elif defined(__rtems__)
rtems_semaphore_release(m_sync);
#elif defined(_POSIX_THREADS)
::pthread_mutex_unlock(&m_sync);
#endif
}
private:
#ifdef _WIN32
CRITICAL_SECTION m_sync;
#elif defined(__rtems__)
rtems_id m_sync;
#elif defined(_POSIX_THREADS)
pthread_mutex_t m_sync;
#endif
};
class PLOG_LINKAGE_HIDDEN MutexLock : NonCopyable
{
public:
MutexLock(Mutex& mutex) : m_mutex(mutex)
{
m_mutex.lock();
}
~MutexLock()
{
m_mutex.unlock();
}
private:
Mutex& m_mutex;
};
template<class T>
#ifdef _WIN32
class Singleton : NonCopyable
#else
class PLOG_LINKAGE Singleton : NonCopyable
#endif
{
public:
#if (defined(__clang__) || defined(__GNUC__) && __GNUC__ >= 8) && !defined(__BORLANDC__)
// This constructor is called before the `T` object is fully constructed, and
// pointers are not dereferenced anyway, so UBSan shouldn't check vptrs.
__attribute__((no_sanitize("vptr")))
#endif
Singleton()
{
assert(!m_instance);
m_instance = static_cast<T*>(this);
}
~Singleton()
{
assert(m_instance);
m_instance = 0;
}
static T* getInstance()
{
return m_instance;
}
private:
static T* m_instance;
};
template<class T>
T* Singleton<T>::m_instance = NULL;
}
}

175
include/plog/WinApi.h Normal file
View file

@ -0,0 +1,175 @@
#pragma once
#ifdef _WIN32
// These windows structs must be in a global namespace
struct HKEY__;
struct _SECURITY_ATTRIBUTES;
struct _CONSOLE_SCREEN_BUFFER_INFO;
struct _RTL_CRITICAL_SECTION;
namespace plog
{
typedef unsigned long DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned int UINT;
typedef int BOOL;
typedef long LSTATUS;
typedef char* LPSTR;
typedef wchar_t* LPWSTR;
typedef const char* LPCSTR;
typedef const wchar_t* LPCWSTR;
typedef void* HANDLE;
typedef HKEY__* HKEY;
typedef size_t ULONG_PTR;
struct CRITICAL_SECTION
{
void* DebugInfo;
long LockCount;
long RecursionCount;
HANDLE OwningThread;
HANDLE LockSemaphore;
ULONG_PTR SpinCount;
};
struct COORD
{
short X;
short Y;
};
struct SMALL_RECT
{
short Left;
short Top;
short Right;
short Bottom;
};
struct CONSOLE_SCREEN_BUFFER_INFO
{
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
};
namespace codePage
{
const UINT kActive = 0;
const UINT kUTF8 = 65001;
#if PLOG_CHAR_IS_UTF8
const UINT kChar = kUTF8;
#else
const UINT kChar = kActive;
#endif
}
namespace eventLog
{
const WORD kErrorType = 0x0001;
const WORD kWarningType = 0x0002;
const WORD kInformationType = 0x0004;
}
namespace hkey
{
const HKEY kLocalMachine = reinterpret_cast<HKEY>(static_cast<ULONG_PTR>(0x80000002));
}
namespace regSam
{
const DWORD kQueryValue = 0x0001;
const DWORD kSetValue = 0x0002;
}
namespace regType
{
const DWORD kExpandSz = 2;
const DWORD kDword = 4;
}
namespace stdHandle
{
const DWORD kOutput = static_cast<DWORD>(-11);
const DWORD kErrorOutput = static_cast<DWORD>(-12);
}
namespace foreground
{
const WORD kBlue = 0x0001;
const WORD kGreen = 0x0002;
const WORD kRed = 0x0004;
const WORD kIntensity = 0x0008;
}
namespace background
{
const WORD kBlue = 0x0010;
const WORD kGreen = 0x0020;
const WORD kRed = 0x0040;
const WORD kIntensity = 0x0080;
}
extern "C"
{
__declspec(dllimport) int __stdcall MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
__declspec(dllimport) int __stdcall WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, const char* lpDefaultChar, BOOL* lpUsedDefaultChar);
__declspec(dllimport) DWORD __stdcall GetCurrentThreadId();
__declspec(dllimport) BOOL __stdcall MoveFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName);
__declspec(dllimport) void __stdcall InitializeCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection);
__declspec(dllimport) void __stdcall EnterCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection);
__declspec(dllimport) void __stdcall LeaveCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection);
__declspec(dllimport) void __stdcall DeleteCriticalSection(_RTL_CRITICAL_SECTION* lpCriticalSection);
__declspec(dllimport) HANDLE __stdcall RegisterEventSourceW(LPCWSTR lpUNCServerName, LPCWSTR lpSourceName);
__declspec(dllimport) BOOL __stdcall DeregisterEventSource(HANDLE hEventLog);
__declspec(dllimport) BOOL __stdcall ReportEventW(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, void* lpUserSid, WORD wNumStrings, DWORD dwDataSize, LPCWSTR* lpStrings, void* lpRawData);
__declspec(dllimport) LSTATUS __stdcall RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, DWORD samDesired, _SECURITY_ATTRIBUTES* lpSecurityAttributes, HKEY* phkResult, DWORD* lpdwDisposition);
__declspec(dllimport) LSTATUS __stdcall RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData);
__declspec(dllimport) LSTATUS __stdcall RegCloseKey(HKEY hKey);
__declspec(dllimport) LSTATUS __stdcall RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, DWORD samDesired, HKEY* phkResult);
__declspec(dllimport) LSTATUS __stdcall RegDeleteKeyW(HKEY hKey, LPCWSTR lpSubKey);
__declspec(dllimport) HANDLE __stdcall GetStdHandle(DWORD nStdHandle);
__declspec(dllimport) BOOL __stdcall WriteConsoleW(HANDLE hConsoleOutput, const void* lpBuffer, DWORD nNumberOfCharsToWrite, DWORD* lpNumberOfCharsWritten, void* lpReserved);
__declspec(dllimport) BOOL __stdcall GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, _CONSOLE_SCREEN_BUFFER_INFO* lpConsoleScreenBufferInfo);
__declspec(dllimport) BOOL __stdcall SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);
__declspec(dllimport) void __stdcall OutputDebugStringW(LPCWSTR lpOutputString);
}
inline void InitializeCriticalSection(CRITICAL_SECTION* criticalSection)
{
plog::InitializeCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection));
}
inline void EnterCriticalSection(CRITICAL_SECTION* criticalSection)
{
plog::EnterCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection));
}
inline void LeaveCriticalSection(CRITICAL_SECTION* criticalSection)
{
plog::LeaveCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection));
}
inline void DeleteCriticalSection(CRITICAL_SECTION* criticalSection)
{
plog::DeleteCriticalSection(reinterpret_cast<_RTL_CRITICAL_SECTION*>(criticalSection));
}
inline BOOL GetConsoleScreenBufferInfo(HANDLE consoleOutput, CONSOLE_SCREEN_BUFFER_INFO* consoleScreenBufferInfo)
{
return plog::GetConsoleScreenBufferInfo(consoleOutput, reinterpret_cast<_CONSOLE_SCREEN_BUFFER_INFO*>(consoleScreenBufferInfo));
}
}
#endif // _WIN32

View file

@ -1,12 +0,0 @@
#include <iostream> // for std::cout
#include "io.h"
// Definition of function main()
int main()
{
int a{readNumber()};
int b{readNumber()};
writeAnswer(a + b);
return 0;
}

View file

View file

15
src/main.cpp Normal file
View file

@ -0,0 +1,15 @@
#include <iostream>
#include <plog/Log.h> // Step1: include the headers
#include "plog/Initializers/RollingFileInitializer.h"
#include "io.h"
// Definition of function main()
int main()
{
plog::init(plog::debug, "../Hello.txt");
PLOGD << "Hello log!";
int a{readNumber()};
int b{readNumber()};
writeAnswer(a + b);
return 0;
}