diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Buffer.cpp | 19 | ||||
-rw-r--r-- | src/common/Exception.cpp | 3 | ||||
-rw-r--r-- | src/common/String.cpp | 33 | ||||
-rw-r--r-- | src/common/SubProcess.cpp | 11 | ||||
-rw-r--r-- | src/common/platform/unix/PosixSpawnSubProcess.cpp | 88 |
5 files changed, 138 insertions, 16 deletions
diff --git a/src/common/Buffer.cpp b/src/common/Buffer.cpp index 67e67735..49a0f8ae 100644 --- a/src/common/Buffer.cpp +++ b/src/common/Buffer.cpp @@ -89,6 +89,15 @@ Index Buffer::PushFront(const std::byte* other, Index other_size, return copy_size; } +bool Buffer::PushBack(std::byte b) { + if (IsUsedReachEnd()) { + return false; + } + ptr_[used_end_] = b; + used_end_++; + return true; +} + Index Buffer::PushBack(const std::byte* other, Index other_size, bool use_memmove) { auto copy_size = std::min(size_ - used_end_, other_size); @@ -138,6 +147,16 @@ Index Buffer::PopEnd(std::byte* buffer, Index size, bool use_memmove) { return pop_size; } +std::byte* Buffer::Detach(Index* size) { + auto ptr = this->ptr_; + if (size) { + *size = this->size_; + } + this->ptr_ = nullptr; + this->size_ = this->used_begin_ = this->used_end_ = 0; + return ptr; +} + void Buffer::Copy_(const Buffer& other) { if (other.ptr_ == nullptr) { ptr_ = nullptr; diff --git a/src/common/Exception.cpp b/src/common/Exception.cpp index 37fa0038..4110ad56 100644 --- a/src/common/Exception.cpp +++ b/src/common/Exception.cpp @@ -5,7 +5,8 @@ #include <cerrno> namespace cru { -Exception::Exception(String message) : message_(std::move(message)) {} +Exception::Exception(String message, std::unique_ptr<std::exception> inner) + : message_(std::move(message)), inner_(std::move(inner)) {} Exception::~Exception() {} diff --git a/src/common/String.cpp b/src/common/String.cpp index 0d1c38b8..b2e52e67 100644 --- a/src/common/String.cpp +++ b/src/common/String.cpp @@ -1,5 +1,6 @@ #include "cru/common/String.h" +#include "cru/common/Buffer.h" #include "cru/common/Exception.h" #include "cru/common/StringToNumberConverter.h" #include "cru/common/StringUtil.h" @@ -31,7 +32,8 @@ String String::FromUtf8(const char* str, Index size) { String result; Utf8CodePointIterator iter(str, size); for (auto cp : iter) { - Utf16EncodeCodePointAppend(cp, result); + Utf16EncodeCodePointAppend( + cp, std::bind(&String::push_back, result, std::placeholders::_1)); } return result; } @@ -260,6 +262,10 @@ bool String::EndWith(StringView str) const { return View().EndWith(str); } std::string String::ToUtf8() const { return View().ToUtf8(); } +Buffer String::ToUtf8Buffer(bool end_zero) const { + return View().ToUtf8Buffer(); +} + String& String::TrimStart() { if (size_ == 0) return *this; @@ -293,7 +299,9 @@ String& String::Trim() { } void String::AppendCodePoint(CodePoint code_point) { - if (!Utf16EncodeCodePointAppend(code_point, *this)) { + if (!Utf16EncodeCodePointAppend( + code_point, + std::bind(&String::push_back, *this, std::placeholders::_1))) { throw TextEncodeException(u"Code point out of range."); } } @@ -523,11 +531,30 @@ Range StringView::RangeFromCodePointToCodeUnit(Range code_point_range) const { std::string StringView::ToUtf8() const { std::string result; for (auto cp : CodePointIterator()) { - Utf8EncodeCodePointAppend(cp, result); + Utf8EncodeCodePointAppend( + cp, std::bind(&std::string::push_back, result, std::placeholders::_1)); } return result; } +Buffer StringView::ToUtf8Buffer(bool end_zero) const { + const Index grow_step = 10; + Buffer buffer(grow_step); // Maybe another init value is more reasonable. + auto push_back = [&buffer](char c) { + if (buffer.IsUsedReachEnd()) { + buffer.ResizeBuffer(buffer.GetBufferSize() + grow_step, true); + } + buffer.PushBack(static_cast<std::byte>(c)); + }; + for (auto cp : CodePointIterator()) { + Utf8EncodeCodePointAppend(cp, push_back); + } + if (end_zero) { + push_back(0); + } + return std::move(buffer); +} + int StringView::ParseToInt(Index* processed_characters_count, unsigned flags, int base) const { return ParseToInteger<int>(processed_characters_count, flags, base); diff --git a/src/common/SubProcess.cpp b/src/common/SubProcess.cpp index 364cd66e..eea83acd 100644 --- a/src/common/SubProcess.cpp +++ b/src/common/SubProcess.cpp @@ -4,17 +4,6 @@ #include <mutex> namespace cru { -SubProcessException::SubProcessException(String message) - : Exception(std::move(message)) {} - -SubProcessException::~SubProcessException() {} - -SubProcessFailedToStartException::SubProcessFailedToStartException( - String message) - : Exception(std::move(message)) {} - -SubProcessFailedToStartException::~SubProcessFailedToStartException() {} - PlatformSubProcessBase::PlatformSubProcessBase( const PlatformSubProcessStartInfo& start_info) : start_info_(start_info), process_lock_(process_mutex_, std::defer_lock) {} diff --git a/src/common/platform/unix/PosixSpawnSubProcess.cpp b/src/common/platform/unix/PosixSpawnSubProcess.cpp index 0eb5615d..8b9a9a47 100644 --- a/src/common/platform/unix/PosixSpawnSubProcess.cpp +++ b/src/common/platform/unix/PosixSpawnSubProcess.cpp @@ -1,8 +1,14 @@ #include "cru/common/platform/unix/PosixSpawnSubProcess.h" +#include "cru/common/Exception.h" +#include "cru/common/Format.h" +#include "cru/common/Guard.h" +#include "cru/common/String.h" #include "cru/common/SubProcess.h" #include <spawn.h> +#include <unistd.h> #include <memory> +#include <unordered_map> namespace cru::platform::unix { PosixSpawnSubProcess::PosixSpawnSubProcess( @@ -40,7 +46,87 @@ io::Stream* PosixSpawnSubProcess::GetStderrStream() { return stderr_buffer_stream_.get(); } -void PosixSpawnSubProcess::PlatformCreateProcess() {} +namespace { +char** CreateCstrArray(const std::vector<String>& argv) { + std::vector<Buffer> utf8_argv; + for (const auto& arg : argv) { + utf8_argv.push_back(arg.ToUtf8Buffer()); + } + char** result = new char*[utf8_argv.size() + 1]; + for (int i = 0; i < utf8_argv.size(); i++) { + result[i] = reinterpret_cast<char*>(utf8_argv[i].Detach()); + } + result[utf8_argv.size()] = nullptr; + return result; +} + +char** CreateCstrArray(const std::unordered_map<String, String>& envp) { + std::vector<String> str_array; + for (auto& [key, value] : envp) { + str_array.push_back(cru::Format(u"{}={}", key, value)); + } + return CreateCstrArray(str_array); +} + +void DestroyCstrArray(char** argv) { + int index = 0; + char* arg = argv[index]; + while (arg) { + delete[] arg; + index++; + arg = argv[index]; + } + delete[] argv; +} +} // namespace + +void PosixSpawnSubProcess::PlatformCreateProcess() { + int error; + auto check_error = [&error](String message) { + if (error == 0) return; + std::unique_ptr<ErrnoException> inner(new ErrnoException({}, error)); + throw SubProcessFailedToStartException(std::move(message), + std::move(inner)); + }; + + posix_spawn_file_actions_t file_actions; + error = posix_spawn_file_actions_init(&file_actions); + check_error(u"Failed to call posix_spawn_file_actions_init."); + Guard file_actions_guard( + [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); + + // dup2 stdin/stdout/stderr + error = posix_spawn_file_actions_adddup2( + &file_actions, stdin_pipe_.GetOtherFileDescriptor(), STDIN_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdin."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stdout_pipe_.GetOtherFileDescriptor(), STDOUT_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdout."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stderr_pipe_.GetOtherFileDescriptor(), STDERR_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stderr."); + + posix_spawnattr_t attr; + error = posix_spawnattr_init(&attr); + check_error(u"Failed to call posix_spawnattr_init."); + Guard attr_guard([&attr] { posix_spawnattr_destroy(&attr); }); + +#ifdef CRU_PLATFORM_OSX + error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); + check_error(u"Failed to set flag POSIX_SPAWN_CLOEXEC_DEFAULT (osx)."); +#endif + + auto exe = start_info_.program.ToUtf8(); + + auto argv = CreateCstrArray(start_info_.arguments); + Guard argv_guard([argv] { DestroyCstrArray(argv); }); + + auto envp = CreateCstrArray(start_info_.environments); + Guard envp_guard([envp] { DestroyCstrArray(envp); }); + + error = posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp); + check_error(u"Failed to call posix_spawnp."); +} PlatformSubProcessExitResult PosixSpawnSubProcess::PlatformWaitForProcess() {} |