This commit is contained in:
2025-12-15 21:42:14 +05:30
parent 1b24256653
commit 4d5d06c3c0
9 changed files with 90 additions and 31 deletions

2
.gitignore vendored
View File

@ -47,5 +47,5 @@
.cache/ .cache/
.local/ .local/
[Bb]uild
out/ out/
[Bb]uild

View File

@ -26,6 +26,8 @@
"rhs": "Windows" "rhs": "Windows"
}, },
"cacheVariables": { "cacheVariables": {
"CMAKE_C_COMPILER": "clang-cl",
"CMAKE_CXX_COMPILER": "clang-cl",
"CMAKE_TOOLCHAIN_FILE": "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "CMAKE_TOOLCHAIN_FILE": "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-windows" "VCPKG_TARGET_TRIPLET": "x64-windows"
} }
@ -42,14 +44,14 @@
}, },
{ {
"name": "windows-default", "name": "windows-default",
"displayName": "Windows (VCPKG)", "displayName": "Windows (Clang-CL + VCPKG)",
"description": "Windows build using VCPKG", "description": "Windows build using Clang-CL and VCPKG dependencies",
"inherits": "windows-base" "inherits": "windows-base"
}, },
{ {
"name": "linux-default", "name": "linux-default",
"displayName": "Linux (System)", "displayName": "Linux (Clang)",
"description": "Linux build using system compilers", "description": "Linux build using Clang",
"inherits": "linux-base" "inherits": "linux-base"
}, },
{ {
@ -58,7 +60,6 @@
"description": "Linux CI Build", "description": "Linux CI Build",
"inherits": "linux-base", "inherits": "linux-base",
"cacheVariables": { "cacheVariables": {
"SDL_UNIX_CONSOLE_BUILD": "ON",
"IS_CI_BUILD": "ON" "IS_CI_BUILD": "ON"
} }
} }
@ -67,7 +68,7 @@
{ {
"name": "windows-debug", "name": "windows-debug",
"configurePreset": "windows-default", "configurePreset": "windows-default",
"configuration": "debug", "configuration": "Debug",
"condition": { "condition": {
"type": "equals", "type": "equals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
@ -77,17 +78,7 @@
{ {
"name": "linux-debug", "name": "linux-debug",
"configurePreset": "linux-default", "configurePreset": "linux-default",
"configuration": "debug", "configuration": "Debug",
"condition": {
"type": "notEquals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "linux-ci-debug",
"configurePreset": "linux-ci",
"configuration": "debug",
"condition": { "condition": {
"type": "notEquals", "type": "notEquals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
@ -97,7 +88,7 @@
{ {
"name": "linux-ci-release", "name": "linux-ci-release",
"configurePreset": "linux-ci", "configurePreset": "linux-ci",
"configuration": "release", "configuration": "Release",
"condition": { "condition": {
"type": "notEquals", "type": "notEquals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",

View File

@ -11,7 +11,7 @@ Originally developed as the internal core for IASoft (PVT) LTD., it is now open-
## ✨ Features ## ✨ Features
* **🚀 High-Performance IPC:** Shared-Memory Ring Buffers with wait-free SPSC synchronization. * **🚀 High-Performance IPC:** Shared-Memory Ring Buffers with wait-free SPSC synchronization.
* **🌐 Networking:** Integrated HTTP/HTTPS client (wrapper around `cpp-httplib` with automatic Zlib/Gzip/Brotli handling). * **🌐 Networking:** Integrated HTTP/HTTPS client (wrapper around `cpp-httplib` with automatic Zlib/Gzip handling).
* **🧵 Async Scheduler:** A job system with high/normal priority queues and work stealing. * **🧵 Async Scheduler:** A job system with high/normal priority queues and work stealing.
* **💾 File I/O:** Memory-mapped file operations and optimized binary stream readers/writers. * **💾 File I/O:** Memory-mapped file operations and optimized binary stream readers/writers.
* **📦 Compression:** Unified API for Zlib, Gzip, and Zstd. * **📦 Compression:** Unified API for Zlib, Gzip, and Zstd.
@ -22,6 +22,8 @@ Originally developed as the internal core for IASoft (PVT) LTD., it is now open-
IACore is built with CMake. You can include it in your project via `FetchContent` or by adding it as a subdirectory. IACore is built with CMake. You can include it in your project via `FetchContent` or by adding it as a subdirectory.
Note: On Windows, you must have VCPKG installed and the VCPKG_ROOT environment variable set, for OpenSSL support.
### CMake Example ### CMake Example
```cmake ```cmake
add_subdirectory(IACore) add_subdirectory(IACore)

View File

@ -37,11 +37,20 @@ target_link_libraries(IACore PRIVATE
target_link_libraries(IACore PUBLIC mimalloc-static) target_link_libraries(IACore PUBLIC mimalloc-static)
if(WIN32)
if(MSVC)
target_link_options(IACore PUBLIC "/INCLUDE:mi_version")
else()
target_link_options(IACore PUBLIC "")
endif()
endif()
target_precompile_headers(IACore PUBLIC inc/IACore/PCH.hpp) target_precompile_headers(IACore PUBLIC inc/IACore/PCH.hpp)
target_compile_options(IACore PRIVATE -fno-exceptions) set(NO_EXCEPT_FLAG "$<IF:$<CXX_COMPILER_ID:MSVC>,/EHs-c-,-fno-exceptions>")
target_compile_options(IACore PRIVATE ${NO_EXCEPT_FLAG})
target_compile_options(IACore INTERFACE target_compile_options(IACore INTERFACE
$<$<NOT:$<BOOL:$<TARGET_PROPERTY:USE_EXCEPTIONS>>>:-fno-exceptions> $<$<NOT:$<BOOL:$<TARGET_PROPERTY:USE_EXCEPTIONS>>>:${NO_EXCEPT_FLAG}>
) )
define_property(TARGET PROPERTY USE_EXCEPTIONS define_property(TARGET PROPERTY USE_EXCEPTIONS

View File

@ -228,11 +228,14 @@ namespace IACore
Expected<SIZE_T, String> FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents, Expected<SIZE_T, String> FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents,
IN BOOL overwrite) IN BOOL overwrite)
{ {
if (!overwrite && FileSystem::exists(path)) const char *mode = overwrite ? "w" : "wx";
return MakeUnexpected(std::format("File aready exists: {}", path.string().c_str())); const auto f = fopen(path.string().c_str(), mode);
const auto f = fopen(path.string().c_str(), "w");
if (!f) if (!f)
{
if (!overwrite && errno == EEXIST)
return MakeUnexpected(std::format("File already exists: {}", path.string().c_str()));
return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str())); return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str()));
}
const auto result = fwrite(contents.data(), 1, contents.size(), f); const auto result = fwrite(contents.data(), 1, contents.size(), f);
fputc(0, f); fputc(0, f);
fclose(f); fclose(f);
@ -242,12 +245,14 @@ namespace IACore
Expected<SIZE_T, String> FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents, Expected<SIZE_T, String> FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents,
IN BOOL overwrite) IN BOOL overwrite)
{ {
if (!overwrite && FileSystem::exists(path)) const char *mode = overwrite ? "w" : "wx";
return MakeUnexpected(std::format("File aready exists: {}", path.string().c_str())); const auto f = fopen(path.string().c_str(), mode);
const auto f = fopen(path.string().c_str(), "wb");
if (!f) if (!f)
{
if (!overwrite && errno == EEXIST)
return MakeUnexpected(std::format("File already exists: {}", path.string().c_str()));
return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str())); return MakeUnexpected(std::format("Failed to write to file: {}", path.string().c_str()));
}
const auto result = fwrite(contents.data(), 1, contents.size(), f); const auto result = fwrite(contents.data(), 1, contents.size(), f);
fclose(f); fclose(f);
return result; return result;

View File

@ -175,6 +175,8 @@ namespace IACore
VOID IPC_Manager::NodeSession::SendPacket(IN UINT16 packetID, IN Span<CONST UINT8> payload) VOID IPC_Manager::NodeSession::SendPacket(IN UINT16 packetID, IN Span<CONST UINT8> payload)
{ {
// Protect the RingBuffer write cursor from concurrent threads
ScopedLock lock(SendMutex);
MONI->Push(packetID, payload); MONI->Push(packetID, payload);
} }

View File

@ -206,19 +206,35 @@ namespace IACore
// Manual Quote-Aware Splitter // Manual Quote-Aware Splitter
std::string currentToken; std::string currentToken;
bool inQuotes = false; bool inQuotes = false;
bool isEscaped = false;
for (char c : args) for (char c : args)
{ {
if (isEscaped)
{
// Previous char was '\', so we treat this char literally.
currentToken += c;
isEscaped = false;
continue;
}
if (c == '\\')
{
// Escape sequence start
isEscaped = true;
continue;
}
if (c == '\"') if (c == '\"')
{ {
// Toggle quote state
inQuotes = !inQuotes; inQuotes = !inQuotes;
// Determine if you want to keep the quotes or strip them.
// Usually for execvp, you strip them so the shell receives the raw content.
continue; continue;
} }
if (c == ' ' && !inQuotes) if (c == ' ' && !inQuotes)
{ {
// Token boundary
if (!currentToken.empty()) if (!currentToken.empty())
{ {
argStorage.push_back(currentToken); argStorage.push_back(currentToken);
@ -230,6 +246,7 @@ namespace IACore
currentToken += c; currentToken += c;
} }
} }
if (!currentToken.empty()) if (!currentToken.empty())
{ {
argStorage.push_back(currentToken); argStorage.push_back(currentToken);

View File

@ -104,6 +104,8 @@ namespace IACore
SteadyTimePoint CreationTime{}; SteadyTimePoint CreationTime{};
SharedPtr<ProcessHandle> ProcessHandle; SharedPtr<ProcessHandle> ProcessHandle;
Mutex SendMutex;
String SharedMemName; String SharedMemName;
PUINT8 MappedPtr{}; PUINT8 MappedPtr{};

View File

@ -212,6 +212,36 @@ BOOL TestMultiLine()
return TRUE; return TRUE;
} }
// -------------------------------------------------------------------------
// 6. Complex Command Line Arguments Handling
// -------------------------------------------------------------------------
BOOL TestComplexArguments()
{
// Should parse as 3 arguments:
// 1. -DDEFINED_MSG="Hello World"
// 2. -v
// 3. path/to/file
String complexArgs = "-DDEFINED_MSG=\\\"Hello World\\\" -v path/to/file";
// We can't easily inspect the child process argv in this unit test framework without
// writing a dedicated child program that prints its argv.
// However, for now, we ensure it doesn't crash or return error code 127.
// Use "echo" to verify what it received.
// Expected output: -DDEFINED_MSG="Hello World" -v path/to/file
String cmd = "/bin/echo";
String captured;
auto result = ProcessOps::SpawnProcessSync(cmd, complexArgs, [&](StringView line) { captured += line; });
IAT_CHECK(result.has_value());
IAT_CHECK_EQ(*result, 0);
// Verify the quotes were preserved in the output if the shell handled them correctly
IAT_CHECK(captured.find("Hello World") != String::npos);
return TRUE;
}
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// Registration // Registration
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
@ -222,6 +252,7 @@ IAT_ADD_TEST(TestExitCodes);
IAT_ADD_TEST(TestMissingExe); IAT_ADD_TEST(TestMissingExe);
IAT_ADD_TEST(TestLargeOutput); IAT_ADD_TEST(TestLargeOutput);
IAT_ADD_TEST(TestMultiLine); IAT_ADD_TEST(TestMultiLine);
IAT_ADD_TEST(TestComplexArguments);
IAT_END_TEST_LIST() IAT_END_TEST_LIST()
IAT_END_BLOCK() IAT_END_BLOCK()