1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-07-02 22:36:00 +02:00
Beef/BeefLibs/corlib/src/Internal.bf

934 lines
23 KiB
Beef

using System.Collections;
using System.Reflection;
using System.Diagnostics;
namespace System
{
struct DbgRawAllocData
{
public Type mType;
public void* mMarkFunc;
public int32 mMaxStackTrace;
public struct Unmarked<T>
{
static DbgRawAllocData sRawAllocData;
public static DbgRawAllocData* Data
{
get
{
if (sRawAllocData.mMaxStackTrace == 0)
{
sRawAllocData.mMarkFunc = null;
sRawAllocData.mMaxStackTrace = 1;
sRawAllocData.mType = typeof(T);
}
return &sRawAllocData;
}
}
}
}
[CRepr]
struct VarArgs
{
#if BF_PLATFORM_WINDOWS || BF_PLATFORM_WASM
void* mVAList;
#else
int[5] mVAList; // Conservative size for va_list
#endif
[Intrinsic("va_start")]
static extern void Start(void* vaList);
[Intrinsic("va_end")]
static extern void End(void* vaList);
[Intrinsic("va_arg")]
static extern void Arg(void* vaList, void* destPtr, int32 typeId);
[Inline]
public mixin Start() mut
{
Start(&mVAList);
}
[Inline]
public mixin End() mut
{
End(&mVAList);
}
[Inline]
public mixin Get<T>() mut
{
T val = ?;
Arg(&mVAList, &val, (.)typeof(T).TypeId);
val
}
public void* ToVAList() mut
{
#if BF_PLATFORM_WINDOWS || BF_PLATFORM_WASM
return mVAList;
#else
return &mVAList;
#endif
}
}
[AlwaysInclude]
static class Internal
{
enum BfObjectFlags : uint8
{
None = 0,
Mark1 = 0x01,
Mark2 = 0x02,
Mark3 = 0x03,
Allocated = 0x04,
StackAlloc = 0x08,
AppendAlloc = 0x10,
AllocInfo = 0x20,
AllocInfo_Short = 0x40,
Deleted = 0x80
};
struct AppendAllocEntry
{
public enum Kind
{
case None;
case Object(Object obj);
case Raw(void* ptr, DbgRawAllocData* allocData);
}
public Kind mKind;
public AppendAllocEntry* mNext;
}
[Intrinsic("cast")]
public static extern Object UnsafeCastToObject(void* ptr);
[Intrinsic("cast")]
public static extern void* UnsafeCastToPtr(Object obj);
[Intrinsic("memcpy")]
public static extern void MemCpy(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false);
[Intrinsic("memmove")]
public static extern void MemMove(void* dest, void* src, int length, int32 align = 1, bool isVolatile = false);
[Intrinsic("memset")]
public static extern void MemSet(void* addr, uint8 val, int length, int32 align = 1, bool isVolatile = false);
[Intrinsic("malloc")]
public static extern void* Malloc(int size);
[Intrinsic("free")]
public static extern void Free(void* ptr);
[LinkName("malloc")]
public static extern void* StdMalloc(int size);
[LinkName("free")]
public static extern void StdFree(void* ptr);
[Intrinsic("returnaddress")]
public static extern void* GetReturnAddress(int32 level = 0);
#if BF_PLATFORM_WASM
static int32 sTestIdx;
static int32 sRanTestCount;
static int32 sErrorCount;
class TestEntry
{
public String mName ~ delete _;
public String mFilePath ~ delete _;
public int mLine;
public int mColumn;
public bool mShouldFail;
public bool mProfile;
public bool mIgnore;
public bool mFailed;
public bool mExecuted;
}
static List<TestEntry> sTestEntries ~ DeleteContainerAndItems!(_);
[CallingConvention(.Cdecl), LinkName("Test_Init_Wasm")]
static void Test_Init(char8* testData)
{
sTestEntries = new .();
for (var cmd in StringView(testData).Split('\n'))
{
List<StringView> cmdParts = scope .(cmd.Split('\t'));
let attribs = cmdParts[1];
TestEntry testEntry = new TestEntry();
testEntry.mName = new String(cmdParts[0]);
testEntry.mFilePath = new String(cmdParts[2]);
testEntry.mLine = int32.Parse(cmdParts[3]).Get();
testEntry.mColumn = int32.Parse(cmdParts[4]).Get();
List<StringView> attributes = scope .(attribs.Split('\a'));
for(var i in attributes)
{
if (i == "Sf")
testEntry.mShouldFail = true;
else if (i == "Pr")
testEntry.mProfile = true;
else if (i == "Ig")
testEntry.mIgnore = true;
else if(i.StartsWith("Name"))
{
testEntry.mName.Clear();
scope String(i.Substring("Name".Length)).Escape(testEntry.mName);
}
}
sTestEntries.Add(testEntry);
}
}
[CallingConvention(.Cdecl), LinkName("Test_Error_Wasm")]
static void Test_Error(char8* error)
{
sErrorCount++;
Debug.WriteLine(scope $"TEST ERROR: {StringView(error)}");
}
[CallingConvention(.Cdecl), LinkName("Test_Write_Wasm")]
static void Test_Write(char8* str)
{
Debug.Write(StringView(str));
}
[CallingConvention(.Cdecl), LinkName("Test_Query_Wasm")]
static int32 Test_Query()
{
while (sTestIdx < sTestEntries.Count)
{
var testEntry = sTestEntries[sTestIdx];
if ((testEntry.mIgnore) || (testEntry.mShouldFail))
{
sTestIdx++;
continue;
}
Debug.WriteLine($"Test '{testEntry.mName}'");
break;
}
sRanTestCount++;
return sTestIdx++;
}
[CallingConvention(.Cdecl), LinkName("Test_Finish_Wasm")]
static void Test_Finish()
{
sRanTestCount--;
String completeStr = scope $"Completed {sRanTestCount} of {sTestEntries.Count} tests.'";
Debug.WriteLine(completeStr);
if (sErrorCount > 0)
{
String failStr = scope $"ERROR: Failed {sErrorCount} test{((sErrorCount != 1) ? "s" : "")}";
Debug.WriteLine(failStr);
}
}
#else
[CallingConvention(.Cdecl)]
static extern void Test_Init(char8* testData);
[CallingConvention(.Cdecl)]
static extern void Test_Error(char8* error);
[CallingConvention(.Cdecl)]
static extern void Test_Write(char8* str);
[CallingConvention(.Cdecl)]
static extern int32 Test_Query();
[CallingConvention(.Cdecl)]
static extern void Test_Finish();
#endif
static void* sModuleHandle;
[AlwaysInclude]
static void SetModuleHandle(void* handle)
{
sModuleHandle = handle;
}
#if !BF_RUNTIME_DISABLE
[CallingConvention(.Cdecl), NoReturn]
public static extern void ThrowIndexOutOfRange(int stackOffset = 0);
[CallingConvention(.Cdecl), NoReturn]
public static extern void ThrowObjectNotInitialized(int stackOffset = 0);
[CallingConvention(.Cdecl), NoReturn]
public static extern void FatalError(String error, int stackOffset = 0);
[CallingConvention(.Cdecl)]
public static extern void* VirtualAlloc(int size, bool canExecute, bool canWrite);
[CallingConvention(.Cdecl)]
public static extern int32 CStrLen(char8* charPtr);
[CallingConvention(.Cdecl)]
public static extern int64 GetTickCountMicro();
[CallingConvention(.Cdecl)]
public static extern void BfDelegateTargetCheck(void* target);
[CallingConvention(.Cdecl), AlwaysInclude]
public static extern void* LoadSharedLibrary(char8* filePath);
[AlwaysInclude, LinkName("Beef_LoadSharedLibraryInto")]
public static void LoadSharedLibraryInto(char8* filePath, void** libDest)
{
if (*libDest == null)
{
if (Runtime.LibraryLoadCallback != null)
*libDest = Runtime.LibraryLoadCallback(filePath);
}
if (*libDest == null)
{
*libDest = LoadSharedLibrary(filePath);
}
}
[CallingConvention(.Cdecl), AlwaysInclude]
public static extern void* GetSharedProcAddress(void* libHandle, char8* procName);
[CallingConvention(.Cdecl), AlwaysInclude]
public static extern void GetSharedProcAddressInto(void* libHandle, char8* procName, void** procDest);
[CallingConvention(.Cdecl)]
public static extern char8* GetCommandLineArgs();
[CallingConvention(.Cdecl)]
public static extern void ProfilerCmd(char8* str);
[CallingConvention(.Cdecl)]
public static extern void ReportMemory();
[CallingConvention(.Cdecl)]
public static extern void ObjectDynCheck(Object obj, int32 typeId, bool allowNull);
[CallingConvention(.Cdecl)]
public static extern void ObjectDynCheckFailed(Object obj, int32 typeId);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectCreated(Object obj, int size, ClassVData* classVData);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectCreatedEx(Object obj, int size, ClassVData* classVData, uint8 allocFlags);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectAllocated(Object obj, int size, ClassVData* classVData);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectAllocatedEx(Object obj, int size, ClassVData* classVData, uint8 allocFlags);
[CallingConvention(.Cdecl)]
public static extern int Dbg_PrepareStackTrace(int baseAllocSize, int maxStackTraceDepth);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectStackInit(Object object, ClassVData* classVData, int size, uint8 allocFlags);
[CallingConvention(.Cdecl)]
public static extern Object Dbg_ObjectAlloc(TypeInstance typeInst, int size);
[CallingConvention(.Cdecl)]
public static extern Object Dbg_ObjectAlloc(ClassVData* classVData, int size, int align, int maxStackTraceDepth, uint8 flags);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectPreDelete(Object obj);
[CallingConvention(.Cdecl)]
public static extern void Dbg_ObjectPreCustomDelete(Object obj);
[CallingConvention(.Cdecl)]
public static extern void Dbg_MarkObjectDeleted(Object obj);
[CallingConvention(.Cdecl)]
public static extern void* Dbg_RawAlloc(int size);
[CallingConvention(.Cdecl)]
public static extern void* Dbg_RawObjectAlloc(int size);
[CallingConvention(.Cdecl)]
public static extern void* Dbg_RawAlloc(int size, DbgRawAllocData* rawAllocData);
[CallingConvention(.Cdecl)]
public static extern void Dbg_RawFree(void* ptr);
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
static void AddAppendInfo(Object rootObj, AppendAllocEntry.Kind kind)
{
Compiler.Assert(sizeof(AppendAllocEntry) <= sizeof(int)*4);
void Handle(AppendAllocEntry* headAllocEntry)
{
if (headAllocEntry.mKind case .None)
{
headAllocEntry.mKind = kind;
}
else
{
AppendAllocEntry* newAppendAllocEntry = (.)new uint8[sizeof(AppendAllocEntry)]*;
newAppendAllocEntry.mKind = kind;
newAppendAllocEntry.mNext = headAllocEntry.mNext;
headAllocEntry.mNext = newAppendAllocEntry;
}
}
if (rootObj.[Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
uint8 allocFlag = (.)(dbgAllocInfo >> 8);
Debug.Assert(allocFlag == 1);
if ((allocFlag & 1) != 0)
{
int allocSize = (.)(dbgAllocInfo >> 16);
int capturedTraceCount = (uint8)(dbgAllocInfo);
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
ptr += allocSize + capturedTraceCount * sizeof(int);
Handle((.)ptr);
}
}
else if (rootObj.[Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
int allocSize = dbgAllocInfo;
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
int info = *(int*)(ptr + allocSize);
int capturedTraceCount = info >> 8;
uint8 allocFlag = (.)info;
Debug.Assert(allocFlag == 1);
if ((allocFlag & 1) != 0)
{
ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int);
Handle((.)ptr);
}
}
}
#endif
public static void Dbg_ObjectAppended(Object rootObj, Object appendObj)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
AddAppendInfo(rootObj, .Object(appendObj));
#endif
}
public static void Dbg_RawAppended(Object rootObj, void* ptr, DbgRawAllocData* rawAllocData)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
AddAppendInfo(rootObj, .Raw(ptr, rawAllocData));
#endif
}
public static void Dbg_MarkAppended(Object rootObj)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
void Handle(AppendAllocEntry* checkAllocEntry)
{
var checkAllocEntry;
while (checkAllocEntry != null)
{
switch (checkAllocEntry.mKind)
{
case .Object(let obj):
obj.[Friend]GCMarkMembers();
case .Raw(let rawPtr, let allocData):
((function void(void*))allocData.mMarkFunc)(rawPtr);
default:
}
checkAllocEntry = checkAllocEntry.mNext;
}
}
if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
uint8 allocFlag = (.)(dbgAllocInfo >> 8);
if ((allocFlag & 1) != 0)
{
int allocSize = (.)(dbgAllocInfo >> 16);
int capturedTraceCount = (uint8)(dbgAllocInfo);
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
ptr += allocSize + capturedTraceCount * sizeof(int);
Handle((.)ptr);
}
}
else if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
int allocSize = dbgAllocInfo;
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
int info = *(int*)(ptr + allocSize);
int capturedTraceCount = info >> 8;
uint8 allocFlag = (.)info;
if ((allocFlag & 1) != 0)
{
ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int);
Handle((.)ptr);
}
}
#endif
}
public static void Dbg_AppendDeleted(Object rootObj, bool doChecks)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
void Handle(AppendAllocEntry* headAllocEntry)
{
AppendAllocEntry* checkAllocEntry = headAllocEntry;
while (checkAllocEntry != null)
{
switch (checkAllocEntry.mKind)
{
case .Object(let obj):
if (doChecks)
{
#unwarn
if (!obj.[DisableObjectAccessChecks]IsDeleted())
{
if (obj.GetType().HasDestructor)
Debug.FatalError("Appended object not deleted with 'delete:append'");
}
}
case .Raw(let rawPtr, let allocData):
default:
}
var nextAllocEntry = checkAllocEntry.mNext;
if (checkAllocEntry == headAllocEntry)
*checkAllocEntry = default;
else
delete (uint8*)checkAllocEntry;
checkAllocEntry = nextAllocEntry;
}
}
if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo_Short != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
uint8 allocFlag = (.)(dbgAllocInfo >> 8);
if ((allocFlag & 1) != 0)
{
int allocSize = (.)(dbgAllocInfo >> 16);
int capturedTraceCount = (uint8)(dbgAllocInfo);
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
ptr += allocSize + capturedTraceCount * sizeof(int);
Handle((.)ptr);
}
}
else if (rootObj.[DisableObjectAccessChecks, Friend]mClassVData & (int)BfObjectFlags.AllocInfo != 0)
{
var dbgAllocInfo = rootObj.[DisableObjectAccessChecks, Friend]mDbgAllocInfo;
int allocSize = dbgAllocInfo;
uint8* ptr = (.)Internal.UnsafeCastToPtr(rootObj);
int info = *(int*)(ptr + allocSize);
int capturedTraceCount = info >> 8;
uint8 allocFlag = (.)info;
if ((allocFlag & 1) != 0)
{
ptr += allocSize + capturedTraceCount * sizeof(int) + sizeof(int);
Handle((.)ptr);
}
}
#endif
}
[CallingConvention(.Cdecl)]
static extern void Shutdown_Internal();
[CallingConvention(.Cdecl), AlwaysInclude]
static void Shutdown()
{
Shutdown_Internal();
Runtime.Shutdown();
}
#else
[NoReturn]
static void Crash()
{
char8* ptr = null;
*ptr = 'A';
}
[AlwaysInclude, NoReturn]
public static void ThrowIndexOutOfRange(int stackOffset = 0)
{
Crash();
}
[AlwaysInclude, NoReturn]
public static void ThrowObjectNotInitialized(int stackOffset = 0)
{
Crash();
}
[AlwaysInclude, NoReturn]
public static void FatalError(String error, int stackOffset = 0)
{
Crash();
}
[AlwaysInclude]
public static void* VirtualAlloc(int size, bool canExecute, bool canWrite)
{
return null;
}
public static int32 CStrLen(char8* charPtr)
{
int32 len = 0;
while (charPtr[len] != 0)
len++;
return len;
}
public static int64 GetTickCountMicro()
{
return 0;
}
[AlwaysInclude]
public static void BfDelegateTargetCheck(void* target)
{
}
[AlwaysInclude]
public static void* LoadSharedLibrary(char8* filePath)
{
return null;
}
[AlwaysInclude]
public static void LoadSharedLibraryInto(char8* filePath, void** libDest)
{
}
[AlwaysInclude]
public static void* GetSharedProcAddress(void* libHandle, char8* procName)
{
return null;
}
[AlwaysInclude]
public static void GetSharedProcAddressInto(void* libHandle, char8* procName, void** procDest)
{
}
[AlwaysInclude]
public static char8* GetCommandLineArgs()
{
return "";
}
public static void ProfilerCmd(char8* str)
{
}
public static void ReportMemory()
{
}
public static void ObjectDynCheck(Object obj, int32 typeId, bool allowNull)
{
}
public static void ObjectDynCheckFailed(Object obj, int32 typeId)
{
}
[DisableChecks, DisableObjectAccessChecks]
public static void Dbg_ObjectCreated(Object obj, int size, ClassVData* classVData)
{
}
[DisableChecks, DisableObjectAccessChecks]
public static void Dbg_ObjectCreatedEx(Object obj, int size, ClassVData* classVData)
{
}
[DisableChecks, DisableObjectAccessChecks]
public static void Dbg_ObjectAllocated(Object obj, int size, ClassVData* classVData)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj.[Friend]mClassVData = (.)(void*)classVData;
obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0);
#else
obj.[Friend]mClassVData = classVData;
#endif
}
[DisableChecks, DisableObjectAccessChecks]
public static void Dbg_ObjectAllocatedEx(Object obj, int size, ClassVData* classVData)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj.[Friend]mClassVData = (.)(void*)classVData;
obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0);
#else
obj.[Friend]mClassVData = classVData;
#endif
}
public static int Dbg_PrepareStackTrace(int baseAllocSize, int maxStackTraceDepth)
{
return 0;
}
[DisableChecks, DisableObjectAccessChecks]
public static void Dbg_ObjectStackInit(Object obj, ClassVData* classVData, int size, uint8 allocFlags)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj.[Friend]mClassVData = (.)(void*)classVData;
obj.[Friend]mClassVData |= (.)BfObjectFlags.StackAlloc;
obj.[Friend]mDbgAllocInfo = (.)GetReturnAddress(0);
#else
obj.[Friend]mClassVData = classVData;
#endif
}
public static Object Dbg_ObjectAlloc(TypeInstance typeInst, int size)
{
return null;
}
public static Object Dbg_ObjectAlloc(ClassVData* classVData, int size, int align, int maxStackTraceDepth, uint8 flags)
{
return null;
}
public static void Dbg_ObjectPreDelete(Object obj)
{
}
public static void Dbg_ObjectPreCustomDelete(Object obj)
{
}
public static void Dbg_MarkObjectDeleted(Object obj)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
obj.[Friend]mClassVData |= (.)BfObjectFlags.Deleted;
#endif
}
public static void* Dbg_RawAlloc(int size)
{
return null;
}
public static void* Dbg_RawObjectAlloc(int size)
{
return null;
}
public static void* Dbg_RawAlloc(int size, DbgRawAllocData* rawAllocData)
{
return null;
}
public static void Dbg_RawFree(void* ptr)
{
}
[AlwaysInclude]
static void Shutdown()
{
}
#endif
[AlwaysInclude]
static void AddRtFlags(int32 flags)
{
Runtime.[Friend]sExtraFlags |= (.)flags;
}
public static T* AllocRawArrayUnmarked<T>(int size)
{
#if BF_ENABLE_REALTIME_LEAK_CHECK
if (Compiler.IsComptime)
return new T[size]*(?);
// We don't want to use the default mark function because the GC will mark the entire array,
// whereas we have a custom marking routine because we only want to mark up to mSize
return (T*)Internal.Dbg_RawAlloc(size * strideof(T), DbgRawAllocData.Unmarked<T>.Data);
#else
return new T[size]*(?);
#endif
}
public static Object ObjectAlloc(TypeInstance typeInst, int size)
{
#if BF_ENABLE_OBJECT_DEBUG_FLAGS
return Dbg_ObjectAlloc(typeInst, size);
#else
void* ptr = Malloc(size);
return *(Object*)(&ptr);
#endif
}
[Error("Cannot be called directly"), SkipCall]
static void SetDeleted1(void* dest);
[Error("Cannot be called directly"), SkipCall]
static void SetDeleted4(void* dest);
[Error("Cannot be called directly"), SkipCall]
static void SetDeleted8(void* dest);
[Error("Cannot be called directly"), SkipCall]
static void SetDeleted16(void* dest);
[Error("Cannot be called directly"), SkipCall]
static extern void SetDeletedX(void* dest, int size);
[Error("Cannot be called directly"), SkipCall]
static extern void SetDeleted(void* dest, int size, int32 align);
[Error("Cannot be called directly"), SkipCall]
static extern void SetDeletedArray(void* dest, int size, int32 align, int arrayCount);
public static int MemCmp(void* memA, void* memB, int length)
{
uint8* p0 = (uint8*)memA;
uint8* p1 = (uint8*)memB;
uint8* end0 = p0 + length;
while (p0 < end0)
{
int diff = *(p0++) - *(p1++);
if (diff != 0)
return diff;
}
return 0;
}
[Inline]
public static int GetArraySize<T>(int length)
{
if (sizeof(T) == strideof(T))
{
return length * sizeof(T);
}
else
{
int size = strideof(T) * (length - 1) + sizeof(T);
if (size < 0)
return 0;
return size;
}
}
public static String[] CreateParamsArray()
{
#if !BF_RUNTIME_DISABLE
char8* cmdLine = GetCommandLineArgs();
//Windows.MessageBoxA(default, scope String()..AppendF("CmdLine: {0}", StringView(cmdLine)), "HI", 0);
String[] strVals = null;
for (int pass = 0; pass < 2; pass++)
{
int argIdx = 0;
void HandleArg(int idx, int len)
{
if (pass == 1)
{
var str = new String(len);
char8* outStart = str.Ptr;
char8* outPtr = outStart;
bool inQuote = false;
for (int i < len)
{
char8 c = cmdLine[idx + i];
if (!inQuote)
{
if (c == '"')
{
inQuote = true;
continue;
}
}
else
{
if (c == '^')
{
i++;
c = cmdLine[idx + i];
}
else if (c == '\"')
{
if (cmdLine[idx + i + 1] == '\"')
{
*(outPtr++) = '\"';
i++;
continue;
}
inQuote = false;
continue;
}
}
*(outPtr++) = c;
}
str.[Friend]mLength = (.)(outPtr - outStart);
strVals[argIdx] = str;
}
++argIdx;
}
int firstCharIdx = -1;
bool inQuote = false;
int i = 0;
while (true)
{
char8 c = cmdLine[i];
if (c == 0)
break;
if ((c.IsWhiteSpace) && (!inQuote))
{
if (firstCharIdx != -1)
{
HandleArg(firstCharIdx, i - firstCharIdx);
firstCharIdx = -1;
}
}
else
{
if (firstCharIdx == -1)
firstCharIdx = i;
if (c == '^')
{
i++;
}
if (c == '"')
inQuote = !inQuote;
else if ((inQuote) && (c == '\\'))
{
c = cmdLine[i + 1];
if (c == '"')
i++;
}
}
i++;
}
if (firstCharIdx != -1)
HandleArg(firstCharIdx, i - firstCharIdx);
if (pass == 0)
strVals = new String[argIdx];
}
return strVals;
#else
return new String[0];
#endif
}
public static void DeleteStringArray(String[] arr)
{
for (var str in arr)
delete str;
delete arr;
}
#if !BF_RUNTIME_DISABLE
extern static this();
extern static ~this();
#endif
}
struct CRTAlloc
{
public void* Alloc(int size, int align)
{
return Internal.StdMalloc(size);
}
public void Free(void* ptr)
{
Internal.StdFree(ptr);
}
}
static
{
public static CRTAlloc gCRTAlloc;
}
}