From ec148a9af83b6236b1a11f6087ad6aa28aabab59 Mon Sep 17 00:00:00 2001 From: VDm Date: Fri, 16 Feb 2024 00:37:18 +0400 Subject: [PATCH 1/7] feat(log): add first SLog functions --- storm/Common.hpp | 16 +++ storm/Log.cpp | 342 +++++++++++++++++++++++++++++++++++++++++++++++ storm/Log.hpp | 13 ++ 3 files changed, 371 insertions(+) create mode 100644 storm/Common.hpp create mode 100644 storm/Log.cpp create mode 100644 storm/Log.hpp diff --git a/storm/Common.hpp b/storm/Common.hpp new file mode 100644 index 0000000..bffb7d5 --- /dev/null +++ b/storm/Common.hpp @@ -0,0 +1,16 @@ +#ifndef STORM_COMMON_HPP +#define STORM_COMMON_HPP + + +#define DECLARE_STRICT_HANDLE(name) \ + typedef struct name##__ { \ + int unused; \ + }* name + +#define DECLARE_DERIVED_HANDLE(name, base) \ + typedef struct name##__ : public base##__ { \ + int unused; \ + }* name + + +#endif diff --git a/storm/Log.cpp b/storm/Log.cpp new file mode 100644 index 0000000..834be7a --- /dev/null +++ b/storm/Log.cpp @@ -0,0 +1,342 @@ +#include "storm/Log.hpp" +#include "storm/Thread.hpp" +#include "storm/Error.hpp" +#include "storm/Memory.hpp" +#include +#include +#if defined(WHOA_SYSTEM_LINUX) +# include +# include +#endif + + +typedef struct _LOG { + HSLOG log; + _LOG* next; + char filename[STORM_MAX_PATH]; + FILE* file; + uint32_t flags; + uint32_t bufferused; + uint32_t pendpoint; + int32_t indent; + int32_t timeStamp; + char buffer[0x10000]; +} LOG; + + +static uint32_t lasttime; +static uint32_t timestrlen; +static char timestr[64]; + +static SCritSect* s_critsect[4]; +static SCritSect* s_defaultdir_critsect; + +static LOG* s_loghead[4]; +static HSLOG s_sequence = 0; + +static char s_defaultdir[STORM_MAX_PATH]; +static bool s_logsysteminit = false; + + +static LOG* LockLog(HSLOG log, HLOCKEDLOG* lockedhandle, bool createifnecessary) { + if (!log) { + *lockedhandle = (HLOCKEDLOG)-1; + return nullptr; + } + + size_t index = reinterpret_cast(log) & 3; + s_critsect[index]->Enter(); + *lockedhandle = (HLOCKEDLOG)index; + + LOG* result = s_loghead[index]; + LOG** p_next = &s_loghead[index]; + + while (result && result->log != log) { + p_next = &result->next; + result = result->next; + } + + if (result) + return result; + + if (createifnecessary) + result = (LOG*)SMemAlloc(sizeof(LOG), __FILE__, __LINE__, 0); + + if (!result) { + s_critsect[index]->Leave(); + *lockedhandle = (HLOCKEDLOG)-1; + return nullptr; + } + + *p_next = result; + result->log = log; + result->next = nullptr; + result->filename[0] = '\0'; + result->file = nullptr; + result->bufferused = 0; + result->pendpoint = 0; + + return result; +} + +static void UnlockLog(HLOCKEDLOG lockedhandle) { + s_critsect[reinterpret_cast(lockedhandle)]->Leave(); +} + +static void UnlockDeleteLog(LOG* logptr, HLOCKEDLOG lockedhandle) { + size_t index = reinterpret_cast(lockedhandle); + LOG* log = s_loghead[index]; + LOG** p_next = &s_loghead[index]; + + while (log && log != logptr) { + p_next = &log->next; + log = log->next; + } + + if (log) { + *p_next = log->next; + SMemFree(log); + } + + s_critsect[index]->Leave(); +} + +static void FlushLog(LOG* logptr) { + if (!logptr->bufferused) + return; + + STORM_ASSERT(logptr->file); + fwrite(logptr->buffer, 1, logptr->bufferused, logptr->file); + fflush(logptr->file); + logptr->bufferused = 0; + logptr->pendpoint = 0; +} + +static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename) +{ + if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) + return filename; + + s_defaultdir_critsect->Enter(); + + if (s_defaultdir[0]) { + SStrCopy(newfilename, s_defaultdir, newfilenamesize); + SStrPack(newfilename, filename, newfilenamesize); + } else { +#if defined(WHOA_SYSTEM_WIN) + GetModuleFileNameA(NULL, newfilename, newfilenamesize); + char* slash = SStrChrR(newfilename, '\\'); + if (slash) + slash[0] = '\0'; + + SStrPack(newfilename, "\\", newfilenamesize); + SStrPack(newfilename, filename, newfilenamesize); +#endif + +#if defined(WHOA_SYSTEM_LINUX) + char buffer[PATH_MAX]; + if (!realpath("/proc/self/exe", buffer)) + buffer[0] = '\0'; + + char* slash = SStrChrR(buffer, '/'); + if (slash) + slash[0] = '\0'; + + SStrCopy(newfilename, buffer, newfilenamesize); + SStrPack(newfilename, "/", newfilenamesize); + SStrPack(newfilename, filename, newfilenamesize); +#endif + +#if defined(WHOA_SYSTEM_MAC) + // TODO: GetModuleFileName() for Mac implementation +#endif + } + + s_defaultdir_critsect->Leave(); + return newfilename; +} + +static size_t PathGetRootChars(const char* path) { + if (path[0] == '/') + return 1; + + size_t length = SStrLen(path); + + if (length < 2) + return 0; + + if (path[1] == ':') + return (path[2] == '\\') ? 3 : 2; + + if (path[0] != '\\' || path[1] != '\\') + return 0; + + const char* v5 = path + 2; + size_t v6 = 2; + do { + if (v5) + v5 = SStrChr(v5, '\\') + 1; + --v6; + } while (v6); + + if (v5) + return v5 - path; + + return length; +} + +static void PathStripFilename(char* path) { + char* v2; // edi + char* v3; // eax + char* v4; // eax + + v2 = SStrChrR(path, '\\'); + v3 = SStrChrR(path, '/'); + if (v2 <= v3) + v2 = v3; + + if (v2) { + v4 = &path[PathGetRootChars(path)]; + if (v2 >= v4) + v2[1] = 0; + else + *v4 = 0; + } +} + +static void PathConvertSlashes(char* path) { + while (*path) { +#if defined(WHOA_SYSTEM_WIN) + if (*path == '/') + *path = '\\'; +#else + if (*path == '\\') + *path = '/'; +#endif + path++; + } +} + +static bool CreateFileDirectory(const char* path) { + STORM_ASSERT(path); + + char buffer[STORM_MAX_PATH]; + SStrCopy(buffer, path, STORM_MAX_PATH); + PathStripFilename(buffer); + + char* v1 = &buffer[PathGetRootChars(buffer)]; + PathConvertSlashes(v1); + + for (size_t i = 0; v1[i]; ++i) { + if (v1[i] != '\\' && v1[i] != '/') + continue; + + char slash = v1[i]; + v1[i] = '\0'; +#if defined(WHOA_SYSTEM_WIN) + CreateDirectoryA(buffer, NULL); +#else + mkdir(buffer, 0755); +#endif + v1[i] = slash; + } + +#if defined(WHOA_SYSTEM_WIN) + return CreateDirectoryA(buffer, NULL); +#else + return !mkdir(buffer, 0755); +#endif +} + +static bool OpenLogFile(const char* filename, FILE** file, uint32_t flags) { + *file = nullptr; + + if (filename && filename[0]) { + char newfilename[STORM_MAX_PATH]; + PrependDefaultDir(newfilename, STORM_MAX_PATH, filename); + CreateFileDirectory(newfilename); + *file = fopen(newfilename, (flags & 2) ? "a+" : "w+"); + return (*file != nullptr); + } + return false; +} + +void SLogInitialize() { + if (s_logsysteminit) + return; + + for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) + s_critsect[i] = new SCritSect(); + + s_defaultdir_critsect = new SCritSect(); + + s_logsysteminit = true; +} + +bool SLogIsInitialized() { + return s_logsysteminit; +} + +void SLogDestroy() { + // TODO: SLogFlushAll(); + // TODO: for (...) { SLogClose } + + for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) + delete s_critsect[i]; + + delete s_defaultdir_critsect; + + s_logsysteminit = false; +} + +uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { + STORM_ASSERT(filename); + STORM_ASSERT(*filename); + STORM_ASSERT(log); + + FILE* file = nullptr; + HLOCKEDLOG lockedhandle; + + *log = 0; + + if (flags & 2) + { + filename = ""; + flags &= ~1u; + } + + if ((flags & 1) == 0 || OpenLogFile(filename, &file, flags)) { + s_sequence = reinterpret_cast(reinterpret_cast(s_sequence) + 1); + *log = s_sequence; + LOG* result = LockLog(s_sequence, &lockedhandle, true); + if (result) { + result->file = file; + SStrCopy(result->filename, filename, STORM_MAX_PATH); + result->flags = flags; + result->timeStamp = 1; + result->indent = 0; + UnlockLog(lockedhandle); + return 1; + } else { + *log = 0; + } + } + return 0; +} + +void SLogClose(HSLOG log) { + if (!s_logsysteminit) + return; + + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (!logptr) + return; + + if (logptr->file) { + FlushLog(logptr); + fclose(logptr->file); + } + + UnlockDeleteLog(logptr, lockedhandle); +} diff --git a/storm/Log.hpp b/storm/Log.hpp new file mode 100644 index 0000000..1a6e376 --- /dev/null +++ b/storm/Log.hpp @@ -0,0 +1,13 @@ +#ifndef STORM_LOG_HPP +#define STORM_LOG_HPP + + +#include "storm/Common.hpp" +#include "storm/String.hpp" + + +DECLARE_STRICT_HANDLE(HSLOG); +DECLARE_STRICT_HANDLE(HLOCKEDLOG); + + +#endif From bc71b135a0f3abddfeafcd4f851be449c1612642 Mon Sep 17 00:00:00 2001 From: VDm Date: Sun, 18 Feb 2024 01:49:12 +0400 Subject: [PATCH 2/7] feat(log): implement all log methods except SLogDump, SLogPend --- storm/Log.cpp | 378 ++++++++++++++++++++++++++++++++++++++++---------- storm/Log.hpp | 15 ++ 2 files changed, 322 insertions(+), 71 deletions(-) diff --git a/storm/Log.cpp b/storm/Log.cpp index 834be7a..f78906e 100644 --- a/storm/Log.cpp +++ b/storm/Log.cpp @@ -4,10 +4,19 @@ #include "storm/Memory.hpp" #include #include +#include #if defined(WHOA_SYSTEM_LINUX) # include # include #endif +#if defined(WHOA_SYSTEM_MAC) +# include +#endif + + +#define STORM_LOG_MAX_CHANNELS 4 +#define STORM_LOG_MAX_BUFFER 0x10000 +#define STORM_LOG_FLUSH_POINT 0xC000 typedef struct _LOG { @@ -16,25 +25,25 @@ typedef struct _LOG { char filename[STORM_MAX_PATH]; FILE* file; uint32_t flags; - uint32_t bufferused; - uint32_t pendpoint; + size_t bufferused; + size_t pendpoint; int32_t indent; int32_t timeStamp; - char buffer[0x10000]; + char buffer[STORM_LOG_MAX_BUFFER]; } LOG; -static uint32_t lasttime; -static uint32_t timestrlen; -static char timestr[64]; +static uint64_t lasttime = 0; +static size_t timestrlen = 0; +static char timestr[64] = { '\0' }; -static SCritSect* s_critsect[4]; -static SCritSect* s_defaultdir_critsect; +static SCritSect* s_critsect[STORM_LOG_MAX_CHANNELS] = { nullptr }; +static SCritSect* s_defaultdir_critsect = nullptr; -static LOG* s_loghead[4]; +static LOG* s_loghead[STORM_LOG_MAX_CHANNELS] = { nullptr }; static HSLOG s_sequence = 0; -static char s_defaultdir[STORM_MAX_PATH]; +static char s_defaultdir[STORM_MAX_PATH] = { '\0' }; static bool s_logsysteminit = false; @@ -56,11 +65,13 @@ static LOG* LockLog(HSLOG log, HLOCKEDLOG* lockedhandle, bool createifnecessary) result = result->next; } - if (result) + if (result) { return result; + } - if (createifnecessary) + if (createifnecessary) { result = (LOG*)SMemAlloc(sizeof(LOG), __FILE__, __LINE__, 0); + } if (!result) { s_critsect[index]->Leave(); @@ -102,8 +113,9 @@ static void UnlockDeleteLog(LOG* logptr, HLOCKEDLOG lockedhandle) { } static void FlushLog(LOG* logptr) { - if (!logptr->bufferused) + if (!logptr->bufferused) { return; + } STORM_ASSERT(logptr->file); fwrite(logptr->buffer, 1, logptr->bufferused, logptr->file); @@ -114,8 +126,9 @@ static void FlushLog(LOG* logptr) { static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename) { - if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) + if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) { return filename; + } s_defaultdir_critsect->Enter(); @@ -126,8 +139,9 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize #if defined(WHOA_SYSTEM_WIN) GetModuleFileNameA(NULL, newfilename, newfilenamesize); char* slash = SStrChrR(newfilename, '\\'); - if (slash) + if (slash) { slash[0] = '\0'; + } SStrPack(newfilename, "\\", newfilenamesize); SStrPack(newfilename, filename, newfilenamesize); @@ -135,12 +149,14 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize #if defined(WHOA_SYSTEM_LINUX) char buffer[PATH_MAX]; - if (!realpath("/proc/self/exe", buffer)) + if (!realpath("/proc/self/exe", buffer)) { buffer[0] = '\0'; + } char* slash = SStrChrR(buffer, '/'); - if (slash) + if (slash) { slash[0] = '\0'; + } SStrCopy(newfilename, buffer, newfilenamesize); SStrPack(newfilename, "/", newfilenamesize); @@ -157,61 +173,71 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize } static size_t PathGetRootChars(const char* path) { - if (path[0] == '/') + if (path[0] == '/') { + if (!SStrCmpI(path, "/Volumes/", 9)) { + const char* offset = SStrChr(path + 9, '/'); + if (offset) { + return offset - path + 1; + } + } return 1; + } - size_t length = SStrLen(path); - - if (length < 2) + if (SStrLen(path) < 2) { return 0; + } - if (path[1] == ':') + if (path[1] == ':') { return (path[2] == '\\') ? 3 : 2; + } - if (path[0] != '\\' || path[1] != '\\') + if (path[0] != '\\' || path[1] != '\\') { return 0; + } - const char* v5 = path + 2; - size_t v6 = 2; - do { - if (v5) - v5 = SStrChr(v5, '\\') + 1; - --v6; - } while (v6); + const char* slash1 = SStrChr(path + 2, '\\'); + if (!slash1) { + return 0; + } - if (v5) - return v5 - path; + const char* slash2 = SStrChr(slash1 + 1, '\\'); + if (!slash2) { + return 0; + } - return length; + return slash2 - path + 1; } static void PathStripFilename(char* path) { - char* v2; // edi - char* v3; // eax - char* v4; // eax + char* slash = SStrChrR(path, '/'); + char* backslash = SStrChrR(path, '\\'); + if (slash <= backslash) { + slash = backslash; + } - v2 = SStrChrR(path, '\\'); - v3 = SStrChrR(path, '/'); - if (v2 <= v3) - v2 = v3; + if (!slash) { + return; + } - if (v2) { - v4 = &path[PathGetRootChars(path)]; - if (v2 >= v4) - v2[1] = 0; - else - *v4 = 0; + char* relative = &path[PathGetRootChars(path)]; + if (slash >= relative) { + slash[1] = 0; + } + else { + relative[0] = 0; } } static void PathConvertSlashes(char* path) { while (*path) { #if defined(WHOA_SYSTEM_WIN) - if (*path == '/') + if (*path == '/') { *path = '\\'; + } #else - if (*path == '\\') + if (*path == '\\') { *path = '/'; + } #endif path++; } @@ -224,21 +250,22 @@ static bool CreateFileDirectory(const char* path) { SStrCopy(buffer, path, STORM_MAX_PATH); PathStripFilename(buffer); - char* v1 = &buffer[PathGetRootChars(buffer)]; - PathConvertSlashes(v1); + char* relative = &buffer[PathGetRootChars(buffer)]; + PathConvertSlashes(relative); - for (size_t i = 0; v1[i]; ++i) { - if (v1[i] != '\\' && v1[i] != '/') + for (size_t i = 0; relative[i]; ++i) { + if (relative[i] != '\\' && relative[i] != '/') { continue; + } - char slash = v1[i]; - v1[i] = '\0'; + char slash = relative[i]; + relative[i] = '\0'; #if defined(WHOA_SYSTEM_WIN) CreateDirectoryA(buffer, NULL); #else mkdir(buffer, 0755); #endif - v1[i] = slash; + relative[i] = slash; } #if defined(WHOA_SYSTEM_WIN) @@ -261,35 +288,124 @@ static bool OpenLogFile(const char* filename, FILE** file, uint32_t flags) { return false; } -void SLogInitialize() { - if (s_logsysteminit) - return; +static void OutputIndent(LOG* logptr) { + int32_t indent = logptr->indent; + if (indent > 0) { + if (indent >= 128) { + indent = 128; + } + memset(&logptr->buffer[logptr->bufferused], ' ', indent); + logptr->buffer[indent + logptr->bufferused] = 0; + logptr->bufferused += indent; + } +} - for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) +static void OutputReturn(LOG* logptr) { + // strcpy(&logptr->buffer[logptr->bufferused], "\r\n"); + // logptr->bufferused += 2; + + // No need to write "\r\n" with fopen() in text mode + logptr->buffer[logptr->bufferused] = '\n'; + logptr->bufferused++; +} + +static void OutputTime(LOG* logptr, bool show) { + if (logptr->timeStamp == 0) { + return; + } + + uint64_t ticks = 0; + +#if defined(WHOA_SYSTEM_WIN) + ticks = GetTickCount64(); +#endif + +#if defined(WHOA_SYSTEM_LINUX) + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts) == 0) { + ticks = ts.tv_sec * 1000 + ts.tv_nsec / 1000000; + } +#endif + +#if defined(WHOA_SYSTEM_MAC) + ticks = mach_absolute_time(); +#endif + + if (ticks != lasttime) { + lasttime = ticks; + + time_t t = time(nullptr); + struct tm* ts = localtime(&t); + // No milliseconds for now + timestrlen = SStrPrintf(timestr, + sizeof(timestr), + "%d/%d %02d:%02d:%02d.%03d ", + ts->tm_mon + 1, + ts->tm_mday, + ts->tm_hour, + ts->tm_min, + ts->tm_sec, + 0); + } + + if (show) { + memcpy(&logptr->buffer[logptr->bufferused], timestr, timestrlen); + } else { + memset(&logptr->buffer[logptr->bufferused], ' ', timestrlen); + } + logptr->bufferused += timestrlen; + logptr->buffer[logptr->bufferused] = '\0'; +} + +static bool PrepareLog(LOG* logptr) { + if (logptr->file) { + return true; + } + + if (OpenLogFile(logptr->filename, &logptr->file, logptr->flags)) { + return true; + } + + logptr->filename[0] = '\0'; + return false; +} + +void SLogInitialize() { + if (s_logsysteminit) { + return; + } + + for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) { s_critsect[i] = new SCritSect(); + } s_defaultdir_critsect = new SCritSect(); s_logsysteminit = true; } -bool SLogIsInitialized() { - return s_logsysteminit; +int SLogIsInitialized() { + return s_logsysteminit ? 1 : 0; } void SLogDestroy() { - // TODO: SLogFlushAll(); - // TODO: for (...) { SLogClose } - - for (size_t i = 0; i < sizeof(s_loghead) / sizeof(s_loghead[0]); ++i) + for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) { + s_critsect[i]->Enter(); + for (LOG* log = s_loghead[i]; log; log = log->next) { + if (log->file) { + FlushLog(log); + fclose(log->file); + } + } + s_critsect[i]->Leave(); delete s_critsect[i]; + } delete s_defaultdir_critsect; - s_logsysteminit = false; } -uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { +int SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { STORM_ASSERT(filename); STORM_ASSERT(*filename); STORM_ASSERT(log); @@ -299,8 +415,7 @@ uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { *log = 0; - if (flags & 2) - { + if (flags & 2) { filename = ""; flags &= ~1u; } @@ -325,13 +440,15 @@ uint32_t SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { } void SLogClose(HSLOG log) { - if (!s_logsysteminit) + if (!s_logsysteminit) { return; + } HLOCKEDLOG lockedhandle; LOG* logptr = LockLog(log, &lockedhandle, false); - if (!logptr) + if (!logptr) { return; + } if (logptr->file) { FlushLog(logptr); @@ -340,3 +457,122 @@ void SLogClose(HSLOG log) { UnlockDeleteLog(logptr, lockedhandle); } + +void SLogFlush(HSLOG log) { + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (logptr) { + if (logptr->file) { + FlushLog(logptr); + } + UnlockLog(lockedhandle); + } +} + +void SLogFlushAll() { + for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) { + s_critsect[i]->Enter(); + for (LOG* log = s_loghead[i]; log; log = log->next) { + if (log->file) { + FlushLog(log); + } + } + s_critsect[i]->Leave(); + } +} + +void SLogGetDefaultDirectory(char* dirname, size_t dirnamesize) { + s_defaultdir_critsect->Enter(); + SStrCopy(dirname, s_defaultdir, dirnamesize); + s_defaultdir_critsect->Leave(); +} + +void SLogSetDefaultDirectory(const char* dirname) { + s_defaultdir_critsect->Enter(); + size_t size = SStrCopy(s_defaultdir, dirname, STORM_MAX_PATH); + PathConvertSlashes(s_defaultdir); +#if defined(WHOA_SYSTEM_WIN) + char slash = '\\'; +#else + char slash = '/'; +#endif + if (size < STORM_MAX_PATH - 1 && s_defaultdir[size - 1] != slash) { + s_defaultdir[size] = slash; + s_defaultdir[size + 1] = 0; + } + s_defaultdir_critsect->Leave(); +} + +int32_t SLogSetAbsIndent(HSLOG log, int32_t indent) { + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (logptr) { + int32_t result = logptr->indent; + logptr->indent = indent; + UnlockLog(lockedhandle); + return result; + } + return 0; +} + +int32_t SLogSetIndent(HSLOG log, int32_t deltaIndent) { + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (logptr) { + int32_t result = logptr->indent; + logptr->indent = result + deltaIndent; + UnlockLog(lockedhandle); + return result; + } + return 0; +} + +void SLogSetTimestamp(HSLOG log, int32_t timeStamp) { + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (logptr) { + logptr->timeStamp = timeStamp; + UnlockLog(lockedhandle); + } +} + +void SLogVWrite(HSLOG log, const char* format, va_list arglist) { + HLOCKEDLOG lockedhandle; + LOG* logptr = LockLog(log, &lockedhandle, false); + if (!logptr) { + return; + } + + if (PrepareLog(logptr)) { + OutputTime(logptr, true); + OutputIndent(logptr); + + int count = vsnprintf( + &logptr->buffer[logptr->bufferused], + STORM_LOG_MAX_BUFFER - logptr->bufferused, + format, + arglist); + if (count > 0) { + logptr->bufferused += count; + } + + OutputReturn(logptr); + +#if defined(WHOA_SYSTEM_WIN) + // if (g_opt.echotooutputdebugstring) + OutputDebugStringA(&logptr->buffer[logptr->pendpoint]); +#endif + + logptr->pendpoint = logptr->bufferused; + if (logptr->bufferused >= STORM_LOG_FLUSH_POINT) { + FlushLog(logptr); + } + } + UnlockLog(lockedhandle); +} + +void SLogWrite(HSLOG log, const char* format, ...) { + va_list arglist; + va_start(arglist, format); + SLogVWrite(log, format, arglist); +} diff --git a/storm/Log.hpp b/storm/Log.hpp index 1a6e376..4e248e2 100644 --- a/storm/Log.hpp +++ b/storm/Log.hpp @@ -10,4 +10,19 @@ DECLARE_STRICT_HANDLE(HSLOG); DECLARE_STRICT_HANDLE(HLOCKEDLOG); +void SLogInitialize(); +int SLogIsInitialized(); +void SLogDestroy(); +int SLogCreate(const char* filename, uint32_t flags, HSLOG* log); +void SLogClose(HSLOG log); +void SLogFlush(HSLOG log); +void SLogFlushAll(); +void SLogGetDefaultDirectory(char* dirname, size_t dirnamesize); +void SLogSetDefaultDirectory(const char* dirname); +int32_t SLogSetAbsIndent(HSLOG log, int32_t indent); +int32_t SLogSetIndent(HSLOG log, int32_t deltaIndent); +void SLogVWrite(HSLOG log, const char* format, va_list arglist); +void SLogWrite(HSLOG log, const char* format, ...); + + #endif From b3ae2d1ebdbdbd0c426fd9d25746b78fcea28c6f Mon Sep 17 00:00:00 2001 From: VDm Date: Sun, 18 Feb 2024 02:45:29 +0400 Subject: [PATCH 3/7] chore(format): fix formatting --- storm/Log.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/storm/Log.cpp b/storm/Log.cpp index f78906e..eb0f65a 100644 --- a/storm/Log.cpp +++ b/storm/Log.cpp @@ -124,8 +124,7 @@ static void FlushLog(LOG* logptr) { logptr->pendpoint = 0; } -static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename) -{ +static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize, const char* filename) { if (!filename || !filename[0] || filename[1] == ':' || SStrChr(filename, '\\') || SStrChr(filename, '/')) { return filename; } @@ -137,7 +136,7 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize SStrPack(newfilename, filename, newfilenamesize); } else { #if defined(WHOA_SYSTEM_WIN) - GetModuleFileNameA(NULL, newfilename, newfilenamesize); + GetModuleFileName(NULL, newfilename, newfilenamesize); char* slash = SStrChrR(newfilename, '\\'); if (slash) { slash[0] = '\0'; @@ -222,8 +221,7 @@ static void PathStripFilename(char* path) { char* relative = &path[PathGetRootChars(path)]; if (slash >= relative) { slash[1] = 0; - } - else { + } else { relative[0] = 0; } } @@ -261,7 +259,7 @@ static bool CreateFileDirectory(const char* path) { char slash = relative[i]; relative[i] = '\0'; #if defined(WHOA_SYSTEM_WIN) - CreateDirectoryA(buffer, NULL); + CreateDirectory(buffer, NULL); #else mkdir(buffer, 0755); #endif @@ -269,7 +267,7 @@ static bool CreateFileDirectory(const char* path) { } #if defined(WHOA_SYSTEM_WIN) - return CreateDirectoryA(buffer, NULL); + return CreateDirectory(buffer, NULL); #else return !mkdir(buffer, 0755); #endif @@ -560,7 +558,7 @@ void SLogVWrite(HSLOG log, const char* format, va_list arglist) { #if defined(WHOA_SYSTEM_WIN) // if (g_opt.echotooutputdebugstring) - OutputDebugStringA(&logptr->buffer[logptr->pendpoint]); + OutputDebugString(&logptr->buffer[logptr->pendpoint]); #endif logptr->pendpoint = logptr->bufferused; From efe062ca6b7771a4b2078a03deffdf049f7dfd8c Mon Sep 17 00:00:00 2001 From: vdm-dev Date: Sun, 18 Feb 2024 15:31:21 +0400 Subject: [PATCH 4/7] fix(build): fix macOS compilation errors --- storm/Log.cpp | 33 +++++++++++++++++++++++++++++---- storm/Log.hpp | 2 ++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/storm/Log.cpp b/storm/Log.cpp index eb0f65a..6ab023a 100644 --- a/storm/Log.cpp +++ b/storm/Log.cpp @@ -5,12 +5,19 @@ #include #include #include +#include + #if defined(WHOA_SYSTEM_LINUX) -# include -# include +#include +#include #endif + #if defined(WHOA_SYSTEM_MAC) -# include +#include +#include +#include +#include +#include #endif @@ -163,7 +170,25 @@ static const char* PrependDefaultDir(char* newfilename, uint32_t newfilenamesize #endif #if defined(WHOA_SYSTEM_MAC) - // TODO: GetModuleFileName() for Mac implementation + newfilename[0] = '\0'; + + char path[PATH_MAX] = {0}; + char actualPath[PATH_MAX] = {0}; + uint32_t size = PATH_MAX; + if (_NSGetExecutablePath(path, &size) == 0) { + if (!realpath(path, actualPath)) { + actualPath[0] = '\0'; + } + } + + char* slash = SStrChrR(actualPath, '/'); + if (slash) { + slash[0] = '\0'; + } + + SStrCopy(newfilename, actualPath, newfilenamesize); + SStrPack(newfilename, "/", newfilenamesize); + SStrPack(newfilename, filename, newfilenamesize); #endif } diff --git a/storm/Log.hpp b/storm/Log.hpp index 4e248e2..fa6f66a 100644 --- a/storm/Log.hpp +++ b/storm/Log.hpp @@ -2,6 +2,8 @@ #define STORM_LOG_HPP +#include + #include "storm/Common.hpp" #include "storm/String.hpp" From b195319ff65d00509d8550b03795045e67c30f25 Mon Sep 17 00:00:00 2001 From: VDm Date: Tue, 20 Feb 2024 00:14:49 +0400 Subject: [PATCH 5/7] chore(log): add SLOG_FLAG_* flags --- storm/Log.cpp | 8 ++++---- storm/Log.hpp | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/storm/Log.cpp b/storm/Log.cpp index 6ab023a..3636243 100644 --- a/storm/Log.cpp +++ b/storm/Log.cpp @@ -305,7 +305,7 @@ static bool OpenLogFile(const char* filename, FILE** file, uint32_t flags) { char newfilename[STORM_MAX_PATH]; PrependDefaultDir(newfilename, STORM_MAX_PATH, filename); CreateFileDirectory(newfilename); - *file = fopen(newfilename, (flags & 2) ? "a+" : "w+"); + *file = fopen(newfilename, (flags & SLOG_FLAG_APPEND) ? "a" : "w"); return (*file != nullptr); } return false; @@ -438,12 +438,12 @@ int SLogCreate(const char* filename, uint32_t flags, HSLOG* log) { *log = 0; - if (flags & 2) { + if (flags & SLOG_FLAG_NO_FILE) { filename = ""; - flags &= ~1u; + flags &= ~SLOG_FLAG_OPEN_FILE; } - if ((flags & 1) == 0 || OpenLogFile(filename, &file, flags)) { + if ((flags & SLOG_FLAG_OPEN_FILE) == 0 || OpenLogFile(filename, &file, flags)) { s_sequence = reinterpret_cast(reinterpret_cast(s_sequence) + 1); *log = s_sequence; LOG* result = LockLog(s_sequence, &lockedhandle, true); diff --git a/storm/Log.hpp b/storm/Log.hpp index fa6f66a..0935d0c 100644 --- a/storm/Log.hpp +++ b/storm/Log.hpp @@ -3,11 +3,19 @@ #include +#include #include "storm/Common.hpp" #include "storm/String.hpp" +enum : uint32_t { + SLOG_FLAG_DEFAULT = 0, // Create or open log file with first SLogWrite() call + SLOG_FLAG_OPEN_FILE = 1, // Create or open log file with SLogCreate() + SLOG_FLAG_NO_FILE = 2, // Don't use log file (use OutputDebugString or console only) + SLOG_FLAG_APPEND = 4 // Don't truncate existing log file +}; + DECLARE_STRICT_HANDLE(HSLOG); DECLARE_STRICT_HANDLE(HLOCKEDLOG); From 96c121717b5e050cb768ffae614aa8d27a42e439 Mon Sep 17 00:00:00 2001 From: VDm Date: Tue, 20 Feb 2024 00:37:21 +0400 Subject: [PATCH 6/7] fix(log): fix SLogDestroy() memory corruption --- storm/Log.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/storm/Log.cpp b/storm/Log.cpp index 3636243..5b3f624 100644 --- a/storm/Log.cpp +++ b/storm/Log.cpp @@ -414,12 +414,17 @@ int SLogIsInitialized() { void SLogDestroy() { for (size_t i = 0; i < STORM_LOG_MAX_CHANNELS; ++i) { s_critsect[i]->Enter(); - for (LOG* log = s_loghead[i]; log; log = log->next) { + LOG* log = s_loghead[i]; + while (log) { if (log->file) { FlushLog(log); fclose(log->file); } + LOG* next = log->next; + SMemFree(log); + log = next; } + s_loghead[i] = nullptr; s_critsect[i]->Leave(); delete s_critsect[i]; } From 786759d49da822f43a25bc3ed83232450e531bb5 Mon Sep 17 00:00:00 2001 From: VDm Date: Tue, 20 Feb 2024 00:38:40 +0400 Subject: [PATCH 7/7] chore(log): add test file --- test/Log.cpp | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 test/Log.cpp diff --git a/test/Log.cpp b/test/Log.cpp new file mode 100644 index 0000000..b5ba959 --- /dev/null +++ b/test/Log.cpp @@ -0,0 +1,51 @@ +#include "storm/Log.hpp" +#include "test/Test.hpp" + + +TEST_CASE("SLogInitialize", "[log]") { + SECTION("constructs correctly") { + SLogInitialize(); + REQUIRE(SLogIsInitialized() == 1); + SLogDestroy(); + } + + SECTION("destructs correctly") { + SLogInitialize(); + SLogDestroy(); + REQUIRE(SLogIsInitialized() == 0); + } +} + +TEST_CASE("SLogCreate", "[log]") { + SECTION("creates new log handle") { + SLogInitialize(); + + HSLOG log; + REQUIRE(SLogCreate("test.log", SLOG_FLAG_DEFAULT, &log) == 1); + REQUIRE(log != 0); + + SLogDestroy(); + } + + SECTION("creates new log file") { + SLogInitialize(); + + HSLOG log; + REQUIRE(SLogCreate("test.log", SLOG_FLAG_OPEN_FILE, &log) == 1); + REQUIRE(log != 0); + + SLogDestroy(); + } +} + +TEST_CASE("SLogWrite", "[log]") { + SLogInitialize(); + + HSLOG log; + REQUIRE(SLogCreate("test.log", SLOG_FLAG_DEFAULT, &log) == 1); + REQUIRE(log != 0); + + SLogWrite(log, "SLogWrite Test"); + + SLogDestroy(); +}