aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/Buffer.cpp19
-rw-r--r--src/common/Exception.cpp3
-rw-r--r--src/common/String.cpp33
-rw-r--r--src/common/SubProcess.cpp11
-rw-r--r--src/common/platform/unix/PosixSpawnSubProcess.cpp88
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() {}