Initial pure C++ implementation
ci / ubuntu-latest (push) Failing after 13s
ci / macos-latest (push) Has been cancelled
ci / windows-latest (push) Has been cancelled

This commit is contained in:
2026-09-25 04:17:30 +08:00
commit 42d6da6302
110 changed files with 37510 additions and 0 deletions
+163
View File
@@ -0,0 +1,163 @@
#include "foundation/fs_utf8.h"
#include <cstring>
#include <fstream>
#include <vector>
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <shellapi.h>
#include <fcntl.h>
#include <io.h>
#else
#include <cstdlib>
#endif
namespace joc::fs_utf8 {
namespace fs = std::filesystem;
fs::path to_path(const std::string& utf8) {
return fs::path(std::u8string(reinterpret_cast<const char8_t*>(utf8.data()), utf8.size()));
}
std::string from_path(const fs::path& path) {
const std::u8string text = path.u8string();
return std::string(reinterpret_cast<const char*>(text.data()), text.size());
}
std::FILE* fopen(const std::string& utf8_path, const char* mode) {
#if defined(_WIN32)
const std::wstring wide_mode(mode, mode + std::strlen(mode));
return ::_wfopen(to_path(utf8_path).c_str(), wide_mode.c_str());
#else
return std::fopen(utf8_path.c_str(), mode);
#endif
}
std::FILE* fopen_spool(const std::string& utf8_path) {
#if defined(_WIN32)
// Delete-on-close handed to the CRT: if the process is killed the file goes with
// it, which is what stops an aborted run from leaving hundreds of gigabytes.
HANDLE handle = ::CreateFileW(
to_path(utf8_path).c_str(), GENERIC_READ | GENERIC_WRITE | DELETE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, nullptr);
if (handle == INVALID_HANDLE_VALUE) {
return nullptr;
}
const int descriptor = ::_open_osfhandle(reinterpret_cast<std::intptr_t>(handle), 0);
if (descriptor == -1) {
::CloseHandle(handle);
return nullptr;
}
return ::_fdopen(descriptor, "wb+");
#else
return std::fopen(utf8_path.c_str(), "wb+");
#endif
}
int remove(const std::string& utf8_path) {
#if defined(_WIN32)
return ::_wremove(to_path(utf8_path).c_str());
#else
return std::remove(utf8_path.c_str());
#endif
}
bool exists(const std::string& utf8_path) {
std::error_code error;
return fs::exists(to_path(utf8_path), error);
}
bool is_directory(const std::string& utf8_path) {
std::error_code error;
return fs::is_directory(to_path(utf8_path), error);
}
std::uintmax_t file_size(const std::string& utf8_path, std::error_code& error) {
return fs::file_size(to_path(utf8_path), error);
}
std::string temp_directory() {
std::error_code error;
const fs::path directory = fs::temp_directory_path(error);
return error ? std::string(".") : from_path(directory);
}
std::string executable_path() {
#if defined(_WIN32)
std::vector<wchar_t> buffer(MAX_PATH);
while (true) {
const DWORD written =
::GetModuleFileNameW(nullptr, buffer.data(), static_cast<DWORD>(buffer.size()));
if (written == 0) {
return std::string();
}
if (written < buffer.size()) {
return from_path(fs::path(std::wstring(buffer.data(), written)));
}
buffer.resize(buffer.size() * 2u);
}
#elif defined(__linux__)
std::vector<char> buffer(4096u, '\0');
const ssize_t written = ::readlink("/proc/self/exe", buffer.data(), buffer.size() - 1u);
return written > 0 ? std::string(buffer.data(), static_cast<std::size_t>(written))
: std::string();
#else
return std::string();
#endif
}
std::ifstream open_input(const std::string& utf8_path) {
return std::ifstream(to_path(utf8_path), std::ios::binary);
}
std::ofstream open_output(const std::string& utf8_path) {
return std::ofstream(to_path(utf8_path), std::ios::binary);
}
std::vector<std::string> command_line_arguments(int argc, char** argv) {
#if defined(_WIN32)
(void)argc;
(void)argv;
int count = 0;
LPWSTR* wide = ::CommandLineToArgvW(::GetCommandLineW(), &count);
std::vector<std::string> arguments;
if (wide == nullptr) {
return arguments;
}
arguments.reserve(static_cast<std::size_t>(count));
for (int index = 0; index < count; ++index) {
const std::wstring_view text(wide[index]);
const int size = ::WideCharToMultiByte(CP_UTF8, 0, text.data(),
static_cast<int>(text.size()), nullptr, 0, nullptr,
nullptr);
std::string utf8(static_cast<std::size_t>(size), '\0');
if (size > 0) {
::WideCharToMultiByte(CP_UTF8, 0, text.data(), static_cast<int>(text.size()),
utf8.data(), size, nullptr, nullptr);
}
arguments.push_back(std::move(utf8));
}
::LocalFree(wide);
return arguments;
#else
std::vector<std::string> arguments;
arguments.reserve(static_cast<std::size_t>(argc));
for (int index = 0; index < argc; ++index) {
arguments.emplace_back(argv[index]);
}
return arguments;
#endif
}
void configure_console() {
#if defined(_WIN32)
::SetConsoleOutputCP(CP_UTF8);
#endif
}
} // namespace joc::fs_utf8