mirror of
https://github.com/ModOrganizer2/mob.git
synced 2026-07-27 14:07:05 -07:00
switched to unicode
changed zlib to use vs instead of jom because it doesn't handle non-ascii characters fixed async_pipe corrupting the stack when io was pending vcvars uses cmd /U to dump `set` to a utf16 file, or else PATH has trouble with non-ascii characters fixed no colors on terminal
This commit is contained in:
+7
-5
@@ -399,10 +399,12 @@ fs::path find_third_party_directory()
|
||||
|
||||
fs::path find_in_path(const std::string& exe)
|
||||
{
|
||||
const std::size_t buffer_size = MAX_PATH;
|
||||
char buffer[buffer_size + 1] = {};
|
||||
const std::wstring wexe = utf8_to_utf16(exe);
|
||||
|
||||
if (SearchPathA(nullptr, exe.c_str(), nullptr, buffer_size, buffer, nullptr))
|
||||
const std::size_t size = MAX_PATH;
|
||||
wchar_t buffer[size + 1] = {};
|
||||
|
||||
if (SearchPathW(nullptr, wexe.c_str(), nullptr, size, buffer, nullptr))
|
||||
return buffer;
|
||||
else
|
||||
return {};
|
||||
@@ -950,7 +952,7 @@ void dump_options()
|
||||
|
||||
string_map tools;
|
||||
for (auto&& [k, v] : g_tools)
|
||||
tools[k] = v.string();
|
||||
tools[k] = path_to_utf8(v);
|
||||
table("tools", tools);
|
||||
|
||||
string_map prebuilt;
|
||||
@@ -962,7 +964,7 @@ void dump_options()
|
||||
|
||||
string_map paths;
|
||||
for (auto&& [k, v] : g_paths)
|
||||
paths[k] = v.string();
|
||||
paths[k] = path_to_utf8(v);
|
||||
table("paths", paths);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -197,8 +197,8 @@ void context::set_log_file(const fs::path& p)
|
||||
{
|
||||
if (!p.empty())
|
||||
{
|
||||
HANDLE h = CreateFileA(
|
||||
p.string().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
HANDLE h = CreateFileW(
|
||||
p.native().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
@@ -242,8 +242,8 @@ void context::emit_log(level lv, const std::string& utf8) const
|
||||
|
||||
if (log_enabled(lv, conf::output_log_level()))
|
||||
{
|
||||
u8cout << utf8 << "\n";
|
||||
auto c = level_color(lv);
|
||||
u8cout << utf8 << "\n";
|
||||
}
|
||||
|
||||
if (g_log_file && log_enabled(lv, conf::file_log_level()))
|
||||
|
||||
+56
-30
@@ -33,15 +33,16 @@ env get_vcvars_env(arch a)
|
||||
|
||||
// "vcvarsall.bat" amd64 && set > temp_file
|
||||
std::string cmd =
|
||||
"\"" + tools::vs::vcvars().string() + "\" " + arch_s +
|
||||
" && set > \"" + tmp.string() + "\"";
|
||||
"\"" + path_to_utf8(tools::vs::vcvars()) + "\" " + arch_s +
|
||||
" && set > \"" + path_to_utf8(tmp) + "\"";
|
||||
|
||||
process::raw(gcx(), cmd)
|
||||
.cmd_unicode(true)
|
||||
.run();
|
||||
|
||||
gcx().trace(context::generic, "reading from {}", tmp);
|
||||
|
||||
std::stringstream ss(op::read_text_file(gcx(), tmp));
|
||||
std::stringstream ss(op::read_text_file(gcx(), encodings::utf16, tmp));
|
||||
op::delete_file(gcx(), tmp);
|
||||
|
||||
env e;
|
||||
@@ -119,7 +120,7 @@ env& env::append_path(const std::vector<fs::path>& v)
|
||||
if (!path.empty())
|
||||
path += ";";
|
||||
|
||||
path += p.string();
|
||||
path += path_to_utf8(p);
|
||||
}
|
||||
|
||||
set("PATH", path, replace);
|
||||
@@ -172,13 +173,15 @@ void env::set_from(const env& e)
|
||||
|
||||
void env::create() const
|
||||
{
|
||||
sys_.clear();
|
||||
|
||||
for (auto&& v : vars_)
|
||||
{
|
||||
string_ += v.first + "=" + v.second;
|
||||
string_.append(1, '\0');
|
||||
sys_ += utf8_to_utf16(v.first + "=" + v.second);
|
||||
sys_.append(1, L'\0');
|
||||
}
|
||||
|
||||
string_.append(1, '\0');
|
||||
sys_.append(1, L'\0');
|
||||
}
|
||||
|
||||
env::map::const_iterator env::find(const std::string& name) const
|
||||
@@ -192,79 +195,102 @@ env::map::const_iterator env::find(const std::string& name) const
|
||||
return vars_.end();
|
||||
}
|
||||
|
||||
void* env::get_pointers() const
|
||||
void* env::get_unicode_pointers() const
|
||||
{
|
||||
if (vars_.empty())
|
||||
return nullptr;
|
||||
|
||||
if (string_.empty())
|
||||
if (sys_.empty())
|
||||
create();
|
||||
|
||||
return (void*)string_.c_str();
|
||||
return (void*)sys_.c_str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void this_env::set(const std::string& k, const std::string& v, env::flags f)
|
||||
{
|
||||
const std::wstring wk = utf8_to_utf16(k);
|
||||
const std::wstring wv = utf8_to_utf16(v);
|
||||
|
||||
switch (f)
|
||||
{
|
||||
case env::replace:
|
||||
::SetEnvironmentVariableA(k.c_str(), v.c_str());
|
||||
{
|
||||
::SetEnvironmentVariableW(wk.c_str(), wv.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case env::append:
|
||||
::SetEnvironmentVariableA(k.c_str(), (get(k) + v).c_str());
|
||||
{
|
||||
const std::wstring current = get_impl(k);
|
||||
::SetEnvironmentVariableW(wk.c_str(), (current + wv).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
case env::prepend:
|
||||
::SetEnvironmentVariableA(k.c_str(), (v + get(k)).c_str());
|
||||
{
|
||||
const std::wstring current = get_impl(k);
|
||||
::SetEnvironmentVariableW(wk.c_str(), (wv + current).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void this_env::prepend_to_path(const fs::path& p)
|
||||
{
|
||||
gcx().trace(context::generic, "prepending to PATH: {}", p);
|
||||
set("PATH", p.string() + ";", env::prepend);
|
||||
set("PATH", path_to_utf8(p) + ";", env::prepend);
|
||||
}
|
||||
|
||||
std::string this_env::get(const std::string& name)
|
||||
{
|
||||
const std::size_t buffer_size = GetEnvironmentVariableA(
|
||||
name.c_str(), nullptr, 0);
|
||||
return utf16_to_utf8(get_impl(name));
|
||||
}
|
||||
|
||||
std::wstring this_env::get_impl(const std::string& k)
|
||||
{
|
||||
const std::wstring wk = utf8_to_utf16(k);
|
||||
|
||||
const std::size_t buffer_size = GetEnvironmentVariableW(
|
||||
wk.c_str(), nullptr, 0);
|
||||
|
||||
if (buffer_size == 0)
|
||||
bail_out("environment variable {} doesn't exist", name);
|
||||
bail_out("environment variable {} doesn't exist", k);
|
||||
|
||||
auto buffer = std::make_unique<char[]>(buffer_size + 1);
|
||||
auto buffer = std::make_unique<wchar_t[]>(buffer_size + 1);
|
||||
std::fill(buffer.get(), buffer.get() + buffer_size + 1, 0);
|
||||
|
||||
GetEnvironmentVariableA(
|
||||
name.c_str(), buffer.get(), static_cast<DWORD>(buffer_size));
|
||||
const std::size_t written = GetEnvironmentVariableW(
|
||||
wk.c_str(), buffer.get(), static_cast<DWORD>(buffer_size));
|
||||
|
||||
return buffer.get();
|
||||
if (written == 0)
|
||||
bail_out("environment variable {} doesn't exist", k);
|
||||
|
||||
MOB_ASSERT((written + 1) == buffer_size);
|
||||
|
||||
return {buffer.get(), buffer.get() + written};
|
||||
}
|
||||
|
||||
env this_env::get()
|
||||
{
|
||||
env e;
|
||||
|
||||
auto free = [](char* p) { FreeEnvironmentStrings(p); };
|
||||
auto free = [](wchar_t* p) { FreeEnvironmentStringsW(p); };
|
||||
|
||||
auto env_block = std::unique_ptr<char, decltype(free)>{
|
||||
GetEnvironmentStrings(), free};
|
||||
auto env_block = std::unique_ptr<wchar_t, decltype(free)>{
|
||||
GetEnvironmentStringsW(), free};
|
||||
|
||||
for (const char* name = env_block.get(); *name != '\0'; )
|
||||
for (const wchar_t* name = env_block.get(); *name != L'\0'; )
|
||||
{
|
||||
const char* equal = std::strchr(name, '=');
|
||||
std::string key(name, static_cast<std::size_t>(equal - name));
|
||||
const wchar_t* equal = std::wcschr(name, '=');
|
||||
std::wstring key(name, static_cast<std::size_t>(equal - name));
|
||||
|
||||
const char* pValue = equal + 1;
|
||||
std::string value(pValue);
|
||||
const wchar_t* pValue = equal + 1;
|
||||
std::wstring value(pValue);
|
||||
|
||||
if (!key.empty())
|
||||
e.set(key, value);
|
||||
e.set(utf16_to_utf8(key), utf16_to_utf8(value));
|
||||
|
||||
name = pValue + value.length() + 1;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ public:
|
||||
|
||||
std::string get(const std::string& k) const;
|
||||
|
||||
void* get_pointers() const;
|
||||
void* get_unicode_pointers() const;
|
||||
|
||||
private:
|
||||
using map = std::map<std::string, std::string>;
|
||||
|
||||
map vars_;
|
||||
mutable std::string string_;
|
||||
mutable std::wstring sys_;
|
||||
|
||||
void create() const;
|
||||
map::const_iterator find(const std::string& name) const;
|
||||
@@ -51,6 +51,9 @@ struct this_env
|
||||
|
||||
static env get();
|
||||
static std::string get(const std::string& k);
|
||||
|
||||
private:
|
||||
static std::wstring get_impl(const std::string& k);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
+2
-2
@@ -320,11 +320,11 @@ int main(int argc, char** argv)
|
||||
|
||||
if (r == 0)
|
||||
{
|
||||
mob::gcx().debug(mob::context::generic, "mob done");
|
||||
mob::gcx().info(mob::context::generic, "mob done");
|
||||
}
|
||||
else
|
||||
{
|
||||
mob::gcx().debug(mob::context::generic,
|
||||
mob::gcx().info(mob::context::generic,
|
||||
"mob finished with exit code {}", r);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -225,8 +225,8 @@ void curl_downloader::on_write(char* ptr, std::size_t n) noexcept
|
||||
|
||||
cx_.trace(context::net, "opening {}", path_);
|
||||
|
||||
HANDLE h = ::CreateFileA(
|
||||
path_.string().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
HANDLE h = ::CreateFileW(
|
||||
path_.native().c_str(), GENERIC_WRITE, FILE_SHARE_READ,
|
||||
nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE)
|
||||
|
||||
+45
-9
@@ -221,7 +221,7 @@ void copy_file_to_dir_if_better(
|
||||
check(cx, dir);
|
||||
}
|
||||
|
||||
if (file.string().find("*") != std::string::npos)
|
||||
if (file.u8string().find(u8"*") != std::string::npos)
|
||||
cx.bail_out(context::fs, "{} contains a glob", file);
|
||||
|
||||
if (!conf::dry())
|
||||
@@ -266,7 +266,7 @@ void copy_file_to_file_if_better(
|
||||
check(cx, dest);
|
||||
}
|
||||
|
||||
if (src.string().find("*") != std::string::npos)
|
||||
if (src.u8string().find(u8"*") != std::string::npos)
|
||||
cx.bail_out(context::fs, "{} contains a glob", src);
|
||||
|
||||
if (!conf::dry())
|
||||
@@ -309,13 +309,13 @@ void copy_glob_to_dir_if_better(
|
||||
const fs::path& src_glob, const fs::path& dest_dir, flags f)
|
||||
{
|
||||
const auto file_parent = src_glob.parent_path();
|
||||
const auto wildcard = src_glob.filename().string();
|
||||
const auto wildcard = src_glob.filename().native();
|
||||
|
||||
for (auto&& e : fs::directory_iterator(file_parent))
|
||||
{
|
||||
const auto name = e.path().filename().string();
|
||||
const auto name = e.path().filename().native();
|
||||
|
||||
if (!PathMatchSpecA(name.c_str(), wildcard.c_str()))
|
||||
if (!PathMatchSpecW(name.c_str(), wildcard.c_str()))
|
||||
{
|
||||
cx.trace(context::fs,
|
||||
"{} did not match {}; skipping", name, wildcard);
|
||||
@@ -355,12 +355,12 @@ void copy_glob_to_dir_if_better(
|
||||
}
|
||||
}
|
||||
|
||||
std::string read_text_file(const context& cx, const fs::path& p, flags f)
|
||||
std::string read_text_file_impl(const context& cx, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "reading {}", p);
|
||||
|
||||
std::string s;
|
||||
std::ifstream in(p);
|
||||
std::ifstream in(p, std::ios::binary);
|
||||
|
||||
in.seekg(0, std::ios::end);
|
||||
s.resize(static_cast<std::size_t>(in.tellg()));
|
||||
@@ -382,6 +382,42 @@ std::string read_text_file(const context& cx, const fs::path& p, flags f)
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string read_text_file(
|
||||
const context& cx, encodings e, const fs::path& p, flags f)
|
||||
{
|
||||
cx.trace(context::fs, "reading {}", p);
|
||||
|
||||
std::string bytes = read_text_file_impl(cx, p, f);
|
||||
if (bytes.empty())
|
||||
return bytes;
|
||||
|
||||
std::string utf8;
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case encodings::utf16:
|
||||
{
|
||||
const auto* wbuf = reinterpret_cast<const wchar_t*>(bytes.data());
|
||||
const std::size_t n = bytes.size() / sizeof(wchar_t);
|
||||
const std::wstring ws(wbuf, wbuf + n);
|
||||
|
||||
utf8 = utf16_to_utf8(ws);
|
||||
break;
|
||||
}
|
||||
|
||||
case encodings::utf8:
|
||||
case encodings::dont_know:
|
||||
default:
|
||||
{
|
||||
utf8 = std::move(bytes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
utf8 = replace_all(utf8, "\r\n", "\n");
|
||||
return utf8;
|
||||
}
|
||||
|
||||
void write_text_file(
|
||||
const context& cx, const fs::path& p, std::string_view s, flags f)
|
||||
{
|
||||
@@ -531,8 +567,8 @@ void check(const context& cx, const fs::path& p)
|
||||
|
||||
auto is_inside = [](auto&& p, auto&& dir)
|
||||
{
|
||||
const std::string s = p.string();
|
||||
const std::string prefix = dir.string();
|
||||
const std::string s = path_to_utf8(p);
|
||||
const std::string prefix = path_to_utf8(dir);
|
||||
|
||||
if (s.size() < prefix.size())
|
||||
return false;
|
||||
|
||||
@@ -52,7 +52,7 @@ void copy_glob_to_dir_if_better(
|
||||
const fs::path& src_glob, const fs::path& dest_dir, flags f);
|
||||
|
||||
std::string read_text_file(
|
||||
const context& cx, const fs::path& p, flags f=noflags);
|
||||
const context& cx, encodings e, const fs::path& p, flags f=noflags);
|
||||
|
||||
void write_text_file(
|
||||
const context& cx, const fs::path& p, std::string_view s, flags f=noflags);
|
||||
|
||||
+91
-48
@@ -15,12 +15,11 @@ const DWORD process_wait_timeout = 50;
|
||||
HANDLE get_bit_bucket()
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa { .nLength = sizeof(sa), .bInheritHandle = TRUE };
|
||||
return ::CreateFileA("NUL", GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
|
||||
return ::CreateFileW(L"NUL", GENERIC_WRITE, 0, &sa, OPEN_EXISTING, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
async_pipe::async_pipe()
|
||||
: pending_(false)
|
||||
: pending_(false), closed_(true)
|
||||
{
|
||||
buffer_ = std::make_unique<char[]>(buffer_size);
|
||||
std::memset(buffer_.get(), 0, buffer_size);
|
||||
@@ -28,6 +27,11 @@ async_pipe::async_pipe()
|
||||
std::memset(&ov_, 0, sizeof(ov_));
|
||||
}
|
||||
|
||||
bool async_pipe::closed() const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
handle_ptr async_pipe::create()
|
||||
{
|
||||
// creating pipe
|
||||
@@ -44,6 +48,7 @@ handle_ptr async_pipe::create()
|
||||
}
|
||||
|
||||
event_.reset(ov_.hEvent);
|
||||
closed_ = false;
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -60,8 +65,8 @@ HANDLE async_pipe::create_pipe()
|
||||
{
|
||||
static std::atomic<int> pipe_id(0);
|
||||
|
||||
const std::string pipe_name_prefix = "\\\\.\\pipe\\mob_pipe";
|
||||
const std::string pipe_name = pipe_name_prefix + std::to_string(++pipe_id);
|
||||
const std::wstring pipe_name =
|
||||
L"\\\\.\\pipe\\mob_pipe" + std::to_wstring(++pipe_id);
|
||||
|
||||
SECURITY_ATTRIBUTES sa = {};
|
||||
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
@@ -71,7 +76,7 @@ HANDLE async_pipe::create_pipe()
|
||||
|
||||
// creating pipe
|
||||
{
|
||||
HANDLE pipe_handle = ::CreateNamedPipeA(
|
||||
HANDLE pipe_handle = ::CreateNamedPipeW(
|
||||
pipe_name.c_str(), PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,
|
||||
PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT,
|
||||
1, buffer_size, buffer_size, pipe_timeout, &sa);
|
||||
@@ -79,7 +84,7 @@ HANDLE async_pipe::create_pipe()
|
||||
if (pipe_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const auto e = GetLastError();
|
||||
bail_out("CreateNamedPipe failed", error_message(e));
|
||||
bail_out("CreateNamedPipeW failed", error_message(e));
|
||||
}
|
||||
|
||||
pipe.reset(pipe_handle);
|
||||
@@ -104,7 +109,7 @@ HANDLE async_pipe::create_pipe()
|
||||
|
||||
|
||||
// creating handle to pipe which is passed to CreateProcess()
|
||||
HANDLE output_write = ::CreateFileA(
|
||||
HANDLE output_write = ::CreateFileW(
|
||||
pipe_name.c_str(), FILE_WRITE_DATA|SYNCHRONIZE, 0,
|
||||
&sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
|
||||
@@ -135,7 +140,8 @@ std::string_view async_pipe::try_read()
|
||||
|
||||
case ERROR_BROKEN_PIPE:
|
||||
{
|
||||
// broken pipe probably means the process is finished
|
||||
// broken pipe means the process is finished
|
||||
closed_ = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -183,7 +189,8 @@ std::string_view async_pipe::check_pending()
|
||||
|
||||
case ERROR_BROKEN_PIPE:
|
||||
{
|
||||
// broken pipe probably means lootcli is finished
|
||||
// broken pipe means the process is finished
|
||||
closed_ = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -222,7 +229,7 @@ process::impl& process::impl::operator=(const impl& i)
|
||||
|
||||
|
||||
process::process()
|
||||
: cx_(&gcx()), flags_(process::noflags), code_(0)
|
||||
: cx_(&gcx()), unicode_(false), flags_(process::noflags), code_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -260,7 +267,7 @@ process& process::name(const std::string& name)
|
||||
std::string process::name() const
|
||||
{
|
||||
if (name_.empty())
|
||||
return bin_.stem().string();
|
||||
return path_to_utf8(bin_.stem());
|
||||
else
|
||||
return name_;
|
||||
}
|
||||
@@ -323,6 +330,12 @@ process& process::stderr_filter(filter_fun f)
|
||||
return *this;
|
||||
}
|
||||
|
||||
process& process::cmd_unicode(bool b)
|
||||
{
|
||||
unicode_ = b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
process& process::external_error_log(const fs::path& p)
|
||||
{
|
||||
error_log_file_ = p;
|
||||
@@ -359,7 +372,7 @@ std::string process::make_cmd() const
|
||||
if (!raw_.empty())
|
||||
return raw_;
|
||||
|
||||
return "\"" + bin_.string() + "\"" + cmd_;
|
||||
return "\"" + path_to_utf8(bin_) + "\"" + cmd_;
|
||||
}
|
||||
|
||||
void process::pipe_into(const process& p)
|
||||
@@ -394,10 +407,10 @@ void process::do_run(const std::string& what)
|
||||
op::delete_file(*cx_, error_log_file_, op::optional);
|
||||
}
|
||||
|
||||
STARTUPINFOA si = { .cb=sizeof(si) };
|
||||
STARTUPINFOW si = { .cb=sizeof(si) };
|
||||
PROCESS_INFORMATION pi = {};
|
||||
|
||||
handle_ptr stdout_pipe, stderr_pipe;
|
||||
handle_ptr stdout_pipe, stderr_pipe, stdin_pipe;
|
||||
|
||||
switch (stdout_.flags)
|
||||
{
|
||||
@@ -445,28 +458,31 @@ void process::do_run(const std::string& what)
|
||||
}
|
||||
}
|
||||
|
||||
si.hStdInput = get_bit_bucket();
|
||||
stdin_pipe.reset(get_bit_bucket());
|
||||
si.hStdInput = stdin_pipe.get();
|
||||
|
||||
si.dwFlags = STARTF_USESTDHANDLES;
|
||||
|
||||
const std::string cmd = this_env::get("COMSPEC");
|
||||
const std::string args = "/C \"" + what + "\"";
|
||||
const std::wstring cmd = utf8_to_utf16(this_env::get("COMSPEC"));
|
||||
std::wstring args = make_cmd_args(what);
|
||||
|
||||
const char* cwd_p = nullptr;
|
||||
std::string cwd_s;
|
||||
const wchar_t* cwd_p = nullptr;
|
||||
std::wstring cwd_s;
|
||||
|
||||
if (!cwd_.empty())
|
||||
{
|
||||
op::create_directories(*cx_, cwd_);
|
||||
cwd_s = cwd_.string();
|
||||
cwd_s = cwd_.native();
|
||||
cwd_p = (cwd_s.empty() ? nullptr : cwd_s.c_str());
|
||||
}
|
||||
|
||||
cx_->trace(context::cmd, "creating process");
|
||||
|
||||
const auto r = ::CreateProcessA(
|
||||
cmd.c_str(), const_cast<char*>(args.c_str()),
|
||||
nullptr, nullptr, TRUE, CREATE_NEW_PROCESS_GROUP,
|
||||
env_.get_pointers(), cwd_p, &si, &pi);
|
||||
const auto r = ::CreateProcessW(
|
||||
cmd.c_str(), args.data(),
|
||||
nullptr, nullptr, TRUE,
|
||||
CREATE_NEW_PROCESS_GROUP|CREATE_UNICODE_ENVIRONMENT,
|
||||
env_.get_unicode_pointers(), cwd_p, &si, &pi);
|
||||
|
||||
if (!r)
|
||||
{
|
||||
@@ -481,6 +497,18 @@ void process::do_run(const std::string& what)
|
||||
impl_.handle.reset(pi.hProcess);
|
||||
}
|
||||
|
||||
std::wstring process::make_cmd_args(const std::string& what) const
|
||||
{
|
||||
std::wstring s;
|
||||
|
||||
if (unicode_)
|
||||
s += L"/U ";
|
||||
|
||||
s += L"/C \"" + utf8_to_utf16(what) + L"\"";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void process::interrupt()
|
||||
{
|
||||
impl_.interrupt = true;
|
||||
@@ -523,30 +551,19 @@ void process::join()
|
||||
cx_->trace(context::cmd, "process interrupted and finished");
|
||||
}
|
||||
|
||||
bool process::read_pipes()
|
||||
void process::read_pipes()
|
||||
{
|
||||
bool read_something = false;
|
||||
|
||||
if (read_pipe(stdout_, impl_.stdout_pipe, context::std_out))
|
||||
read_something = true;
|
||||
|
||||
if (read_pipe(stderr_, impl_.stderr_pipe, context::std_err))
|
||||
read_something = true;
|
||||
|
||||
return read_something;
|
||||
read_pipe(stdout_, impl_.stdout_pipe, context::std_out);
|
||||
read_pipe(stderr_, impl_.stderr_pipe, context::std_err);
|
||||
}
|
||||
|
||||
bool process::read_pipe(stream& s, async_pipe& pipe, context::reason r)
|
||||
void process::read_pipe(stream& s, async_pipe& pipe, context::reason r)
|
||||
{
|
||||
bool read_something = false;
|
||||
|
||||
switch (s.flags)
|
||||
{
|
||||
case forward_to_log:
|
||||
{
|
||||
const std::string_view buffer = pipe.read();
|
||||
if (!buffer.empty())
|
||||
read_something = true;
|
||||
|
||||
for_each_line(buffer, [&](auto&& line)
|
||||
{
|
||||
@@ -562,15 +579,14 @@ bool process::read_pipe(stream& s, async_pipe& pipe, context::reason r)
|
||||
cx_->log(f.r, f.lv, "{}", f.line);
|
||||
});
|
||||
|
||||
s.string.append(buffer.begin(), buffer.end());
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case keep_in_string:
|
||||
{
|
||||
const std::string_view buffer = pipe.read();
|
||||
if (!buffer.empty())
|
||||
read_something = true;
|
||||
|
||||
s.string.append(buffer.begin(), buffer.end());
|
||||
break;
|
||||
}
|
||||
@@ -579,8 +595,6 @@ bool process::read_pipe(stream& s, async_pipe& pipe, context::reason r)
|
||||
case inherit:
|
||||
break;
|
||||
}
|
||||
|
||||
return read_something;
|
||||
}
|
||||
|
||||
void process::on_completed()
|
||||
@@ -588,7 +602,9 @@ void process::on_completed()
|
||||
// one last time
|
||||
for (;;)
|
||||
{
|
||||
if (!read_pipes())
|
||||
read_pipes();
|
||||
|
||||
if (impl_.stdout_pipe.closed() && impl_.stderr_pipe.closed())
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -620,6 +636,7 @@ void process::on_completed()
|
||||
else
|
||||
{
|
||||
dump_error_log_file();
|
||||
dump_stderr();
|
||||
cx_->bail_out(context::cmd, "{} returned {}", make_name(), code_);
|
||||
}
|
||||
}
|
||||
@@ -669,7 +686,7 @@ void process::dump_error_log_file() noexcept
|
||||
if (fs::exists(error_log_file_))
|
||||
{
|
||||
std::string log = op::read_text_file(
|
||||
*cx_, error_log_file_, op::optional);
|
||||
*cx_, encodings::dont_know, error_log_file_, op::optional);
|
||||
|
||||
if (log.empty())
|
||||
return;
|
||||
@@ -694,6 +711,32 @@ void process::dump_error_log_file() noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void process::dump_stderr() noexcept
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!stderr_.string.empty())
|
||||
{
|
||||
cx_->error(context::cmd,
|
||||
"{} failed, content of stderr:", make_name());
|
||||
|
||||
for_each_line(stderr_.string, [&](auto&& line)
|
||||
{
|
||||
cx_->error(context::cmd, " {}", line);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
cx_->error(context::cmd,
|
||||
"{} failed, stderr was empty", make_name());
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// eat it
|
||||
}
|
||||
}
|
||||
|
||||
int process::exit_code() const
|
||||
{
|
||||
return static_cast<int>(code_);
|
||||
@@ -752,7 +795,7 @@ std::string process::arg_to_string(const std::string& s, bool force_quote)
|
||||
|
||||
std::string process::arg_to_string(const fs::path& p, bool)
|
||||
{
|
||||
return "\"" + p.string() + "\"";
|
||||
return "\"" + path_to_utf8(p) + "\"";
|
||||
}
|
||||
|
||||
std::string process::arg_to_string(const url& u, bool force_quote)
|
||||
|
||||
+10
-3
@@ -16,7 +16,8 @@ public:
|
||||
async_pipe();
|
||||
|
||||
handle_ptr create();
|
||||
std::string_view read();
|
||||
std::string_view read();
|
||||
bool closed() const;
|
||||
|
||||
private:
|
||||
static const std::size_t buffer_size = 50'000;
|
||||
@@ -26,6 +27,7 @@ private:
|
||||
std::unique_ptr<char[]> buffer_;
|
||||
OVERLAPPED ov_;
|
||||
bool pending_;
|
||||
bool closed_;
|
||||
|
||||
HANDLE create_pipe();
|
||||
std::string_view try_read();
|
||||
@@ -111,6 +113,8 @@ public:
|
||||
process& stderr_level(context::level lv);
|
||||
process& stderr_filter(filter_fun f);
|
||||
|
||||
process& cmd_unicode(bool b);
|
||||
|
||||
process& external_error_log(const fs::path& p);
|
||||
|
||||
process& flags(flags_t f);
|
||||
@@ -182,6 +186,7 @@ private:
|
||||
std::string name_;
|
||||
fs::path bin_;
|
||||
fs::path cwd_;
|
||||
bool unicode_;
|
||||
flags_t flags_;
|
||||
stream stdout_;
|
||||
stream stderr_;
|
||||
@@ -195,15 +200,17 @@ private:
|
||||
|
||||
std::string make_name() const;
|
||||
std::string make_cmd() const;
|
||||
std::wstring make_cmd_args(const std::string& what) const;
|
||||
void pipe_into(const process& p);
|
||||
|
||||
void do_run(const std::string& what);
|
||||
bool read_pipes();
|
||||
bool read_pipe(stream& s, async_pipe& pipe, context::reason r);
|
||||
void read_pipes();
|
||||
void read_pipe(stream& s, async_pipe& pipe, context::reason r);
|
||||
|
||||
void on_completed();
|
||||
void on_timeout(bool& already_interrupted);
|
||||
void dump_error_log_file() noexcept;
|
||||
void dump_stderr() noexcept;
|
||||
|
||||
void add_arg(const std::string& k, const std::string& v, arg_flags f);
|
||||
|
||||
|
||||
+2
-2
@@ -111,8 +111,8 @@ void pyqt::sip_build()
|
||||
python::source_path(),
|
||||
python::scripts_path()})
|
||||
.set("CL", " /MP")
|
||||
.set("LIB", ";" + paths::install_libs().string(), env::append)
|
||||
.set("PYTHONHOME", python::source_path().string());
|
||||
.set("LIB", ";" + path_to_utf8(paths::install_libs()), env::append)
|
||||
.set("PYTHONHOME", path_to_utf8(python::source_path()));
|
||||
|
||||
|
||||
bypass_file built_bypass(cx(), source_path(), "built");
|
||||
|
||||
@@ -127,12 +127,12 @@ void python::build_and_install_from_source()
|
||||
"python", "pythonw", "python3dll", "select", "pyexpat",
|
||||
"unicodedata", "_queue", "_bz2", "_ssl"})
|
||||
.parameters({
|
||||
"bz2Dir=" + bzip2::source_path().string(),
|
||||
"zlibDir=" + zlib::source_path().string(),
|
||||
"opensslIncludeDir=" + openssl::include_path().string(),
|
||||
"opensslOutDir=" + openssl::source_path().string(),
|
||||
"libffiIncludeDir=" + libffi::include_path().string(),
|
||||
"libffiOutDir=" + libffi::lib_path().string()}));
|
||||
"bz2Dir=" + path_to_utf8(bzip2::source_path()),
|
||||
"zlibDir=" + path_to_utf8(zlib::source_path()),
|
||||
"opensslIncludeDir=" + path_to_utf8(openssl::include_path()),
|
||||
"opensslOutDir=" + path_to_utf8(openssl::source_path()),
|
||||
"libffiIncludeDir=" + path_to_utf8(libffi::include_path()),
|
||||
"libffiOutDir=" + path_to_utf8(libffi::lib_path())}));
|
||||
|
||||
package();
|
||||
install_pip();
|
||||
|
||||
+3
-4
@@ -41,13 +41,12 @@ void zlib::do_fetch()
|
||||
void zlib::do_build_and_install()
|
||||
{
|
||||
const auto build_path = run_tool(cmake()
|
||||
.generator(cmake::jom)
|
||||
.generator(cmake::vs)
|
||||
.root(source_path())
|
||||
.prefix(source_path()));
|
||||
|
||||
run_tool(jom()
|
||||
.path(build_path)
|
||||
.target("install"));
|
||||
run_tool(msbuild()
|
||||
.solution(source_path() / "vsbuild" / "INSTALL.vcxproj"));
|
||||
|
||||
op::copy_file_to_dir_if_better(cx(),
|
||||
build_path / "zconf.h",
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ cmake& cmake::def(const std::string& name, const std::string& value)
|
||||
|
||||
cmake& cmake::def(const std::string& name, const fs::path& p)
|
||||
{
|
||||
def(name, p.string());
|
||||
def(name, path_to_utf8(p));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ void extractor::do_run()
|
||||
// so the handling of a duplicate directory is done manually in
|
||||
// check_duplicate_directory() below
|
||||
|
||||
if (file_.string().ends_with(".tar.gz"))
|
||||
if (file_.u8string().ends_with(u8".tar.gz"))
|
||||
{
|
||||
cx_->trace(context::generic, "this is a tar.gz, piping");
|
||||
|
||||
@@ -109,7 +109,7 @@ void extractor::do_run()
|
||||
|
||||
void extractor::check_duplicate_directory(const fs::path& ifile)
|
||||
{
|
||||
const auto dir_name = where_.filename().string();
|
||||
const auto dir_name = where_.filename();
|
||||
|
||||
// check for a folder with the same name
|
||||
if (!fs::exists(where_ / dir_name))
|
||||
@@ -160,7 +160,7 @@ void extractor::check_duplicate_directory(const fs::path& ifile)
|
||||
|
||||
// give it a temp name in case there's yet another directory with the
|
||||
// same name in it
|
||||
const auto temp_dir = where_ / ("_mob_" + dir_name );
|
||||
const auto temp_dir = where_ / (u8"_mob_" + dir_name.u8string());
|
||||
|
||||
cx_->trace(context::generic,
|
||||
"renaming dir to {} to avoid clashes", temp_dir);
|
||||
|
||||
@@ -25,6 +25,7 @@ int basic_process_runner::execute_and_join()
|
||||
process_.set_context(cx_);
|
||||
process_.run();
|
||||
join();
|
||||
|
||||
return process_.exit_code();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -483,7 +483,7 @@ std::string cp_to_utf8(std::string_view s)
|
||||
return *s8;
|
||||
}
|
||||
|
||||
std::string path_to_utf8(const fs::path& p)
|
||||
std::string path_to_utf8(fs::path p)
|
||||
{
|
||||
return utf16_to_utf8(p.native());
|
||||
}
|
||||
|
||||
+13
-1
@@ -32,6 +32,14 @@ inline void mob_assert(
|
||||
}
|
||||
|
||||
|
||||
enum class encodings
|
||||
{
|
||||
dont_know = 0,
|
||||
utf8,
|
||||
utf16
|
||||
};
|
||||
|
||||
|
||||
class context;
|
||||
class url;
|
||||
|
||||
@@ -214,7 +222,11 @@ std::string trim_copy(const std::string& s, const std::string& what=" \t\r\n");
|
||||
|
||||
std::wstring utf8_to_utf16(std::string_view s);
|
||||
std::string utf16_to_utf8(std::wstring_view ws);
|
||||
std::string path_to_utf8(const fs::path& p);
|
||||
|
||||
template <class T>
|
||||
std::string path_to_utf8(T&&) = delete;
|
||||
|
||||
std::string path_to_utf8(fs::path p);
|
||||
|
||||
|
||||
class u8stream
|
||||
|
||||
+2
-2
@@ -22,13 +22,13 @@
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
Reference in New Issue
Block a user