diff --git a/BeefLibs/corlib/src/Net/Socket.bf b/BeefLibs/corlib/src/Net/Socket.bf index dcc2bc75..d1ae74a3 100644 --- a/BeefLibs/corlib/src/Net/Socket.bf +++ b/BeefLibs/corlib/src/Net/Socket.bf @@ -395,8 +395,6 @@ namespace System.Net int32 size = sizeof(SockAddr_in); if (bind(mHandle, &service, size) == SOCKET_ERROR) { - int err = WSAGetLastError(); - Close(); return .Err; } diff --git a/BeefLibs/corlib/src/Windows.bf b/BeefLibs/corlib/src/Windows.bf index be1ce04f..afaafe64 100644 --- a/BeefLibs/corlib/src/Windows.bf +++ b/BeefLibs/corlib/src/Windows.bf @@ -1715,6 +1715,9 @@ namespace System [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] public static extern HWnd SetForegroundWindow(HWnd wnd); + [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] + public static extern HWnd ShowWindow(HWnd wnd, int32 cmdShow); + [Import("user32.lib"), CLink, CallingConvention(.Stdcall)] public static extern HWnd GetForegroundWindow(); diff --git a/BeefTools/LogViewer/src/Board.bf b/BeefTools/LogViewer/src/Board.bf index a76b8e37..1f6d624a 100644 --- a/BeefTools/LogViewer/src/Board.bf +++ b/BeefTools/LogViewer/src/Board.bf @@ -31,6 +31,9 @@ namespace LogViewer public List mNewMatches ~ delete _; public bool mRefreshing; + public String mFilePath ~ delete _; + public String mMemLogName ~ delete _; + public uint32[] mColors = new .( 0xFFFFFFFF, 0xFFFC5858, @@ -54,6 +57,7 @@ namespace LogViewer ewc.mFont = gApp.mFont; ewc.mWordWrap = false; ewc.mTextColors = mColors; + ewc.mIsReadOnly = true; mDocEdit.InitScrollbars(true, true); AddWidget(mDocEdit); @@ -79,6 +83,12 @@ namespace LogViewer public void Load(StringView filePath) { + DeleteAndNullify!(mFilePath); + DeleteAndNullify!(mMemLogName); + mFilePath = new .(filePath); + + mWidgetWindow.SetTitle(scope $"LogViewer - {mFilePath}"); + scope AutoBeefPerf("Board.Load"); delete mContent; @@ -89,9 +99,45 @@ namespace LogViewer { gApp.Fail("Failed to open file '{0}'", filePath); } + + mFilterDirtyCountdown = 1; + //Refresh(); //mDocEdit.SetText(mContent); } + [CallingConvention(.Stdcall), CLink] + static extern char8* MemLogger_Get(char8* name); + + public void LoadMemLog(StringView name) + { + DeleteAndNullify!(mFilePath); + DeleteAndNullify!(mMemLogName); + mMemLogName = new .(name); + + mWidgetWindow.SetTitle(scope $"LogViewer - {mMemLogName}"); + + var result = MemLogger_Get(name.ToScopeCStr!()); + if (result == null) + { + gApp.Fail("Failed to open MemLog '{0}'", name); + return; + } + + delete mContent; + mContent = new String(); + mContent.Append(result); + + mFilterDirtyCountdown = 1; + } + + public void Reload() + { + if (mFilePath != null) + Load(mFilePath); + if (mMemLogName != null) + LoadMemLog(mMemLogName); + } + void Refresh() { scope AutoBeefPerf("Board.Refresh"); @@ -105,37 +151,40 @@ namespace LogViewer let filters = mFilter.Split!('\n'); - for (var line in mContent.Split('\n')) + if (mContent != null) { - bool hadMatch = false; - bool hadFilter = false; - - for (var filter in filters) + for (var line in mContent.Split('\n')) { - if (filter.Length == 0) - continue; - hadFilter = true; - int lastIdx = -1; - while (true) + bool hadMatch = false; + bool hadFilter = false; + + for (var filter in filters) { - int findIdx = line.IndexOf(filter, lastIdx + 1); - if (findIdx == -1) - break; + if (filter.Length == 0) + continue; + hadFilter = true; + int lastIdx = -1; + while (true) + { + int findIdx = line.IndexOf(filter, lastIdx + 1); + if (findIdx == -1) + break; - hadMatch = true; - lastIdx = findIdx + filter.Length - 1; + hadMatch = true; + lastIdx = findIdx + filter.Length - 1; - Match match; - match.mFilterIdx = (.)@filter; - match.mTextIdx = (.)(mNewContent.Length + findIdx); - mNewMatches.Add(match); + Match match; + match.mFilterIdx = (.)@filter; + match.mTextIdx = (.)(mNewContent.Length + findIdx); + mNewMatches.Add(match); + } } - } - if ((hadMatch) || (!hadFilter)) - { - mNewContent.Append(line); - mNewContent.Append('\n'); + if ((hadMatch) || (!hadFilter)) + { + mNewContent.Append(line); + mNewContent.Append('\n'); + } } } diff --git a/BeefTools/LogViewer/src/LVApp.bf b/BeefTools/LogViewer/src/LVApp.bf index cbf80e79..9824e04b 100644 --- a/BeefTools/LogViewer/src/LVApp.bf +++ b/BeefTools/LogViewer/src/LVApp.bf @@ -8,6 +8,7 @@ using Beefy.utils; using System.IO; using System.Diagnostics; using System.Threading; +using Beefy.sys; namespace LogViewer { @@ -26,7 +27,7 @@ namespace LogViewer { base.Init(); - var dialog = scope OpenFileDialog(); + /*var dialog = scope OpenFileDialog(); dialog.SetFilter("All files (*.*)|*.*"); dialog.InitialDirectory = mInstallDir; dialog.Title = "Open Log"; @@ -35,7 +36,7 @@ namespace LogViewer { Stop(); return; - } + }*/ BeefPerf.Init("127.0.0.1", "LogViewer"); @@ -45,7 +46,7 @@ namespace LogViewer BFWindow.Flags windowFlags = BFWindow.Flags.Border | //BFWindow.Flags.SysMenu | //| BFWindow.Flags.CaptureMediaKeys | BFWindow.Flags.Caption | BFWindow.Flags.Minimize | BFWindow.Flags.QuitOnClose | BFWindowBase.Flags.Resizable | - BFWindow.Flags.SysMenu; + BFWindow.Flags.SysMenu | .Menu; mFont = new Font(); float fontSize = 12; @@ -55,17 +56,43 @@ namespace LogViewer mFont.AddAlternate("Segoe UI Emoji", fontSize); mBoard = new Board(); - mBoard.Load(dialog.FileNames[0]); - mMainWindow = new WidgetWindow(null, "LogViewer", 0, 0, 1600, 1200, windowFlags, mBoard); + //mBoard.Load(dialog.FileNames[0]); + mMainWindow = new WidgetWindow(null, "LogViewer", 20, 20, 1600, 1200, windowFlags, mBoard); //mMainWindow.mWindowKeyDownDelegate.Add(new => SysKeyDown); mMainWindow.SetMinimumSize(480, 360); mMainWindow.mIsMainWindow = true; + + SysMenu root = mMainWindow.mSysMenu; + var subMenu = root.AddMenuItem("&File"); + subMenu.AddMenuItem("&Open", "Ctrl+O", new (menu) => + { + var dialog = scope OpenFileDialog(); + dialog.SetFilter("All files (*.*)|*.*"); + dialog.InitialDirectory = mInstallDir; + dialog.Title = "Open Log"; + let result = dialog.ShowDialog(); + if ((result case .Err) || (dialog.FileNames.Count == 0)) + { + Stop(); + return; + } + mBoard.Load(dialog.FileNames[0]); + }); + subMenu.AddMenuItem("Read &MemLog", "Ctrl+M", new (menu) => + { + var dialog = new MemLogDialog(); + dialog.PopupWindow(mMainWindow); + }); + subMenu.AddMenuItem("&Reload", "Ctrl+R", new (menu) => + { + mBoard.Reload(); + }); } public void Fail(String str, params Object[] paramVals) { var errStr = scope String(); - errStr.AppendF(str, paramVals); + errStr.AppendF(str, params paramVals); Fail(errStr); } diff --git a/BeefTools/LogViewer/src/MemLogDialog.bf b/BeefTools/LogViewer/src/MemLogDialog.bf new file mode 100644 index 00000000..8128b9e8 --- /dev/null +++ b/BeefTools/LogViewer/src/MemLogDialog.bf @@ -0,0 +1,21 @@ +using Beefy.theme.dark; +using Beefy.widgets; + +namespace LogViewer; + +class MemLogDialog : DarkDialog +{ + EditWidget mEditWidget; + + public this() : base("Open MemLog", "MemLog Name") + { + + mDefaultButton = AddButton("OK", new (evt) => + { + var name = mEditWidget.GetText(.. scope .()); + gApp.mBoard.LoadMemLog(name); + }); + mEscButton = AddButton("Cancel", new (evt) => Close()); + mEditWidget = AddEdit(""); + } +} \ No newline at end of file diff --git a/BeefySysLib/BeefySysLib.cpp b/BeefySysLib/BeefySysLib.cpp index bfaf3143..3c6858c9 100644 --- a/BeefySysLib/BeefySysLib.cpp +++ b/BeefySysLib/BeefySysLib.cpp @@ -10,6 +10,7 @@ #include "util/Vector.h" #include "util/PerfTimer.h" #include "util/TLSingleton.h" +#include "util/MemLogger.h" #include "img/ImgEffects.h" #include "util/AllocDebug.h" @@ -926,4 +927,36 @@ BF_EXPORT void BF_CALLTYPE BF_Test() for (int i : iArr) OutputDebugStrF("Hey %d\n", i); -} \ No newline at end of file +} + +BF_EXPORT void* BF_CALLTYPE MemLogger_Create(const char* memName, int size) +{ + MemLogger* memLogger = new MemLogger(); + if (!memLogger->Create(memName, size)) + { + delete memLogger; + return NULL; + } + return memLogger; +} + +BF_EXPORT void BF_CALLTYPE MemLogger_Write(MemLogger* memLogger, void* ptr, int size) +{ + memLogger->Write(ptr, size); +} + +BF_EXPORT void BF_CALLTYPE MemLogger_Delete(MemLogger* memLogger) +{ + delete memLogger; +} + +BF_EXPORT const char* BF_CALLTYPE MemLogger_Get(const char* memName) +{ + MemLogger memLogger; + + String& outString = *gBeefySys_TLStrReturn.Get(); + outString.Clear(); + if (!memLogger.Get(memName, outString)) + return NULL; + return outString.c_str(); +} diff --git a/BeefySysLib/BeefySysLib.vcxproj b/BeefySysLib/BeefySysLib.vcxproj index 24f095c5..5d01f54e 100644 --- a/BeefySysLib/BeefySysLib.vcxproj +++ b/BeefySysLib/BeefySysLib.vcxproj @@ -1950,6 +1950,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + @@ -2189,6 +2190,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\" + diff --git a/BeefySysLib/BeefySysLib.vcxproj.filters b/BeefySysLib/BeefySysLib.vcxproj.filters index 55154045..5b40e16d 100644 --- a/BeefySysLib/BeefySysLib.vcxproj.filters +++ b/BeefySysLib/BeefySysLib.vcxproj.filters @@ -743,6 +743,9 @@ src\img + + src\util + @@ -1147,6 +1150,9 @@ src\img + + src\util + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj b/BeefySysLib/BeefySysLib_static.vcxproj index ac170baa..9dc0b08d 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj +++ b/BeefySysLib/BeefySysLib_static.vcxproj @@ -880,6 +880,7 @@ + @@ -1047,6 +1048,7 @@ + diff --git a/BeefySysLib/BeefySysLib_static.vcxproj.filters b/BeefySysLib/BeefySysLib_static.vcxproj.filters index 9bc062c7..cbe3e70f 100644 --- a/BeefySysLib/BeefySysLib_static.vcxproj.filters +++ b/BeefySysLib/BeefySysLib_static.vcxproj.filters @@ -593,6 +593,9 @@ src\img + + src\util + @@ -913,6 +916,9 @@ src\img + + src\util + diff --git a/BeefySysLib/Common.cpp b/BeefySysLib/Common.cpp index a8dcb36c..d37473de 100644 --- a/BeefySysLib/Common.cpp +++ b/BeefySysLib/Common.cpp @@ -660,7 +660,7 @@ void Beefy::ExactMinimalDoubleToStr(double d, char* str) static char* StbspCallback(char *buf, void *user, int len) { - ((String*)user)->Append(buf, len); + ((StringImpl*)user)->Append(buf, len); return buf; } @@ -821,6 +821,12 @@ String Beefy::vformat(const char* fmt, va_list argPtr) BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr); return str; } + +void Beefy::vformat(StringImpl& str, const char* fmt, va_list argPtr) +{ + char buf[STB_SPRINTF_MIN]; + BF_stbsp_vsprintfcb(StbspCallback, (void*)&str, buf, fmt, argPtr); +} #endif String Beefy::StrFormat(const char* fmt ...) diff --git a/BeefySysLib/Common.h b/BeefySysLib/Common.h index 49a9c4c4..3cfa130c 100644 --- a/BeefySysLib/Common.h +++ b/BeefySysLib/Common.h @@ -195,6 +195,7 @@ uint64 BFGetTickCountMicro(); uint64 BFGetTickCountMicroFast(); extern String vformat(const char* fmt, va_list argPtr); +extern void vformat(StringImpl& str, const char* fmt, va_list argPtr); extern String StrFormat(const char* fmt ...); void ExactMinimalFloatToStr(float f, char* str); void ExactMinimalDoubleToStr(double d, char* str); diff --git a/BeefySysLib/util/MemLogger.cpp b/BeefySysLib/util/MemLogger.cpp new file mode 100644 index 00000000..29af8db7 --- /dev/null +++ b/BeefySysLib/util/MemLogger.cpp @@ -0,0 +1,161 @@ +#include "MemLogger.h" + +USING_NS_BF; + +struct MemLogger_Header +{ +public: + int mHead; + int mTail; + int mSize; +}; + +MemLogger::MemLogger() +{ + mFileMap = NULL; + mMemBuffer = NULL; + mBufferSize = 0; + mTotalWriteSize = 0; +} + +MemLogger::~MemLogger() +{ + if (mMemBuffer != NULL) + ::UnmapViewOfFile(mMemBuffer); + if (mFileMap != NULL) + ::CloseHandle(mFileMap); +} + +void MemLogger::Write(const void* ptr, int size) +{ + if (mMemBuffer == NULL) + return; + if (size == 0) + return; + + int dataSize = mBufferSize - sizeof(MemLogger_Header); + void* dataPtr = (uint8*)mMemBuffer + sizeof(MemLogger_Header); + + MemLogger_Header* header = (MemLogger_Header*)mMemBuffer; + + bool wasWrapped = header->mHead < header->mTail; + + int writeSize = BF_MIN(size, dataSize - header->mHead); + memcpy((char*)dataPtr + header->mHead, ptr, writeSize); + size -= writeSize; + + header->mHead += writeSize; + while (header->mHead >= dataSize) + header->mHead -= dataSize; + + if (size > 0) + { + int writeSize2 = BF_MIN(size, dataSize - header->mHead); + memcpy((char*)dataPtr + header->mHead, (char*)ptr + writeSize, writeSize2); + header->mHead += writeSize2; + while (header->mHead >= dataSize) + header->mHead -= dataSize; + } + + mTotalWriteSize += writeSize; + + if (mTotalWriteSize >= dataSize) + { + header->mTail = header->mHead + 1; + if (header->mTail > dataSize) + header->mTail -= dataSize; + } +} + +bool Beefy::MemLogger::Create(const StringImpl& memName, int size) +{ + String sharedName = "MemLogger_" + memName; + HANDLE hMapFile = CreateFileMappingA( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // maximum object size (high-order DWORD) + size, // maximum object size (low-order DWORD) + sharedName.c_str()); // name of mapping object + + if (hMapFile == NULL) + return false; + + mMemBuffer = MapViewOfFile(hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + size); + + if (mMemBuffer == NULL) + return false; + + mBufferSize = size; + + MemLogger_Header* header = (MemLogger_Header*)mMemBuffer; + header->mHead = 0; + header->mTail = 0; + header->mSize = size; + return true; +} + +bool Beefy::MemLogger::Get(const StringImpl& memName, String& outStr) +{ + String sharedName = "MemLogger_" + memName; + HANDLE hMapFile = ::OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, FALSE, sharedName.c_str()); + if (hMapFile == NULL) + return false; + + void* memPtr = MapViewOfFile(hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(MemLogger_Header)); + + MemLogger_Header* header = (MemLogger_Header*)(memPtr); + int size = header->mSize; + UnmapViewOfFile(memPtr); + + memPtr = MapViewOfFile(hMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + size); + + if (memPtr == NULL) + return false; + + ::CloseHandle(hMapFile); + + header = (MemLogger_Header*)(memPtr); + + int dataSize = header->mSize - sizeof(MemLogger_Header); + void* dataPtr = (uint8*)memPtr + sizeof(MemLogger_Header); + + if (header->mHead >= header->mTail) + { + // Not wrapped around + outStr.Insert(outStr.mLength, (char*)dataPtr + header->mTail, header->mHead - header->mTail); + } + else + { + outStr.Insert(outStr.mLength, (char*)dataPtr + header->mTail, dataSize - header->mTail); + outStr.Insert(outStr.mLength, (char*)dataPtr, header->mHead); + } + + return true; +} + +void Beefy::MemLogger::Log(const char* fmt ...) +{ + if (mMemBuffer == NULL) + return; + + StringT<4096> str; + va_list argList; + va_start(argList, fmt); + vformat(str, fmt, argList); + va_end(argList); + + Write(str.c_str(), str.mLength); +} diff --git a/BeefySysLib/util/MemLogger.h b/BeefySysLib/util/MemLogger.h new file mode 100644 index 00000000..bc505c31 --- /dev/null +++ b/BeefySysLib/util/MemLogger.h @@ -0,0 +1,28 @@ +#pragma once + +#include "../Common.h" + +NS_BF_BEGIN + +class MemLogger +{ +public: + HANDLE mFileMap; + void* mMemBuffer; + int mBufferSize; + int mTotalWriteSize; + +public: + MemLogger(); + + ~MemLogger(); + + bool Create(const StringImpl& memName, int size); + bool Get(const StringImpl& memName, String& outStr); + void Log(const char* fmt ...); + void Write(const void* ptr, int size); +}; + + + +NS_BF_END