mirror of https://github.com/bsnes-emu/bsnes.git
160 lines
4.5 KiB
C++
160 lines
4.5 KiB
C++
#pragma once
|
|
|
|
//auto execute(const string& name, const string& args...) -> string;
|
|
//[[synchronous]]
|
|
//executes program, waits for completion, and returns data written to stdout
|
|
|
|
//auto invoke(const string& name, const string& args...) -> void;
|
|
//[[asynchronous]]
|
|
//if a program is specified, it is executed with the arguments provided
|
|
//if a file is specified, the file is opened using the program associated with said file type
|
|
//if a folder is specified, the folder is opened using the associated file explorer
|
|
//if a URL is specified, the default web browser is opened and pointed at the URL requested
|
|
|
|
#include <nall/intrinsics.hpp>
|
|
#include <nall/string.hpp>
|
|
|
|
namespace nall {
|
|
|
|
#if defined(PLATFORM_MACOSX) || defined(PLATFORM_LINUX) || defined(PLATFORM_BSD)
|
|
|
|
template<typename... P> inline auto execute(const string& name, P&&... p) -> string {
|
|
int fd[2];
|
|
if(pipe(fd) == -1) return "";
|
|
|
|
pid_t pid = fork();
|
|
if(pid == 0) {
|
|
const char* argv[1 + sizeof...(p) + 1];
|
|
const char** argp = argv;
|
|
lstring argl(forward<P>(p)...);
|
|
*argp++ = (const char*)name;
|
|
for(auto& arg : argl) *argp++ = (const char*)arg;
|
|
*argp++ = nullptr;
|
|
|
|
dup2(fd[1], STDOUT_FILENO);
|
|
dup2(fd[1], STDERR_FILENO);
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
execvp(name, (char* const*)argv);
|
|
//this is called only if execvp fails:
|
|
//use _exit instead of exit, to avoid destroying key shared file descriptors
|
|
_exit(0);
|
|
} else {
|
|
close(fd[1]);
|
|
|
|
string result;
|
|
while(true) {
|
|
char buffer[256];
|
|
auto size = read(fd[0], buffer, sizeof(buffer));
|
|
if(size <= 0) break;
|
|
|
|
auto offset = result.size();
|
|
result.resize(offset + size);
|
|
memory::copy(result.get() + offset, buffer, size);
|
|
}
|
|
|
|
close(fd[0]);
|
|
wait(nullptr);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
template<typename... P> inline auto invoke(const string& name, P&&... p) -> void {
|
|
pid_t pid = fork();
|
|
if(pid == 0) {
|
|
const char* argv[1 + sizeof...(p) + 1];
|
|
const char** argp = argv;
|
|
lstring argl(forward<P>(p)...);
|
|
*argp++ = (const char*)name;
|
|
for(auto& arg : argl) *argp++ = (const char*)arg;
|
|
*argp++ = nullptr;
|
|
|
|
if(execvp(name, (char* const*)argv) < 0) {
|
|
execlp("xdg-open", "xdg-open", (const char*)name, nullptr);
|
|
}
|
|
exit(0);
|
|
}
|
|
}
|
|
|
|
#elif defined(PLATFORM_WINDOWS)
|
|
|
|
template<typename... P> inline auto execute(const string& name, P&&... p) -> string {
|
|
lstring argl(name, forward<P>(p)...);
|
|
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
|
|
string arguments = argl.merge(" ");
|
|
|
|
SECURITY_ATTRIBUTES sa;
|
|
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = true;
|
|
sa.lpSecurityDescriptor = nullptr;
|
|
|
|
HANDLE stdoutRead;
|
|
HANDLE stdoutWrite;
|
|
if(!CreatePipe(&stdoutRead, &stdoutWrite, &sa, 0)) return "";
|
|
if(!SetHandleInformation(stdoutRead, HANDLE_FLAG_INHERIT, 0)) return "";
|
|
|
|
HANDLE stdinRead;
|
|
HANDLE stdinWrite;
|
|
if(!CreatePipe(&stdinRead, &stdinWrite, &sa, 0)) return "";
|
|
if(!SetHandleInformation(stdinWrite, HANDLE_FLAG_INHERIT, 0)) return "";
|
|
|
|
STARTUPINFO si;
|
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
si.hStdError = stdoutWrite;
|
|
si.hStdOutput = stdoutWrite;
|
|
si.hStdInput = stdinRead;
|
|
si.dwFlags = STARTF_USESTDHANDLES;
|
|
|
|
PROCESS_INFORMATION pi;
|
|
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
if(!CreateProcess(
|
|
nullptr, utf16_t(arguments),
|
|
nullptr, nullptr, true, CREATE_NO_WINDOW,
|
|
nullptr, nullptr, &si, &pi
|
|
)) return "";
|
|
|
|
if(WaitForSingleObject(pi.hProcess, INFINITE)) return "";
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
string result;
|
|
while(true) {
|
|
char buffer[256];
|
|
DWORD read, available, remaining;
|
|
if(!PeekNamedPipe(stdoutRead, nullptr, sizeof(buffer), &read, &available, &remaining)) break;
|
|
if(read == 0) break;
|
|
|
|
if(!ReadFile(stdoutRead, buffer, sizeof(buffer), &read, nullptr)) break;
|
|
if(read == 0) break;
|
|
|
|
auto offset = result.size();
|
|
result.resize(offset + read);
|
|
memory::copy(result.get() + offset, buffer, read);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template<typename... P> inline auto invoke(const string& name, P&&... p) -> void {
|
|
lstring argl(forward<P>(p)...);
|
|
for(auto& arg : argl) if(arg.find(" ")) arg = {"\"", arg, "\""};
|
|
string arguments = argl.merge(" ");
|
|
ShellExecute(nullptr, nullptr, utf16_t(name), utf16_t(arguments), nullptr, SW_SHOWNORMAL);
|
|
}
|
|
|
|
#else
|
|
|
|
template<typename... P> inline auto execute(const string& name, P&&... p) -> string {
|
|
return "";
|
|
}
|
|
|
|
template<typename... P> inline auto invoke(const string& name, P&&... p) -> void {
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|