|
@@ -8,7 +8,9 @@
|
|
|
#include "core/strings/string_stream.h"
|
|
#include "core/strings/string_stream.h"
|
|
|
|
|
|
|
|
#if CROWN_PLATFORM_POSIX
|
|
#if CROWN_PLATFORM_POSIX
|
|
|
- #include <unistd.h> // fork, execv
|
|
|
|
|
|
|
+ #include <unistd.h> // fork, execvp
|
|
|
|
|
+ #include <sys/wait.h> // waitpid
|
|
|
|
|
+ #include <errno.h>
|
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
|
#include <windows.h>
|
|
#include <windows.h>
|
|
|
#endif
|
|
#endif
|
|
@@ -19,6 +21,7 @@ struct Private
|
|
|
{
|
|
{
|
|
|
#if CROWN_PLATFORM_POSIX
|
|
#if CROWN_PLATFORM_POSIX
|
|
|
FILE* file;
|
|
FILE* file;
|
|
|
|
|
+ pid_t pid;
|
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
|
PROCESS_INFORMATION process;
|
|
PROCESS_INFORMATION process;
|
|
|
#endif
|
|
#endif
|
|
@@ -29,7 +32,7 @@ namespace process_internal
|
|
|
bool is_open(Private* priv)
|
|
bool is_open(Private* priv)
|
|
|
{
|
|
{
|
|
|
#if CROWN_PLATFORM_POSIX
|
|
#if CROWN_PLATFORM_POSIX
|
|
|
- return priv->file != NULL;
|
|
|
|
|
|
|
+ return priv->pid != -1;
|
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
|
return priv->process.hProcess != 0;
|
|
return priv->process.hProcess != 0;
|
|
|
#endif
|
|
#endif
|
|
@@ -42,7 +45,7 @@ Process::Process()
|
|
|
Private* priv = (Private*)_data;
|
|
Private* priv = (Private*)_data;
|
|
|
|
|
|
|
|
#if CROWN_PLATFORM_POSIX
|
|
#if CROWN_PLATFORM_POSIX
|
|
|
- priv->file = NULL;
|
|
|
|
|
|
|
+ priv->pid = -1;
|
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
|
memset(&priv->process, 0, sizeof(priv->process));
|
|
memset(&priv->process, 0, sizeof(priv->process));
|
|
|
#endif
|
|
#endif
|
|
@@ -54,20 +57,85 @@ Process::~Process()
|
|
|
CE_ENSURE(process_internal::is_open(priv) == false);
|
|
CE_ENSURE(process_internal::is_open(priv) == false);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-s32 Process::spawn(const char* const* argv)
|
|
|
|
|
|
|
+s32 Process::spawn(const char* const* argv, u32 flags)
|
|
|
{
|
|
{
|
|
|
Private* priv = (Private*)_data;
|
|
Private* priv = (Private*)_data;
|
|
|
CE_ENSURE(process_internal::is_open(priv) == false);
|
|
CE_ENSURE(process_internal::is_open(priv) == false);
|
|
|
|
|
|
|
|
|
|
+#if CROWN_PLATFORM_POSIX
|
|
|
|
|
+ // https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/popen.c.auto.html
|
|
|
|
|
+ int fildes[2];
|
|
|
|
|
+ pid_t pid;
|
|
|
|
|
+
|
|
|
|
|
+ if (flags & ProcessFlags::STDIN_PIPE || flags & ProcessFlags::STDOUT_PIPE)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (pipe(fildes) < 0)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pid = fork();
|
|
|
|
|
+ if (pid == -1) // Error, cleanup and return
|
|
|
|
|
+ {
|
|
|
|
|
+ close(fildes[0]);
|
|
|
|
|
+ close(fildes[1]);
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (pid == 0) // Child
|
|
|
|
|
+ {
|
|
|
|
|
+ if (flags & ProcessFlags::STDOUT_PIPE)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (fildes[1] != STDOUT_FILENO)
|
|
|
|
|
+ {
|
|
|
|
|
+ dup2(fildes[1], STDOUT_FILENO);
|
|
|
|
|
+ close(fildes[1]);
|
|
|
|
|
+ fildes[1] = STDOUT_FILENO;
|
|
|
|
|
+ }
|
|
|
|
|
+ close(fildes[0]);
|
|
|
|
|
+
|
|
|
|
|
+ if (flags & ProcessFlags::STDERR_MERGE)
|
|
|
|
|
+ {
|
|
|
|
|
+ dup2(fildes[1], 2);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (flags & ProcessFlags::STDIN_PIPE)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (fildes[0] != STDIN_FILENO)
|
|
|
|
|
+ {
|
|
|
|
|
+ dup2(fildes[0], STDIN_FILENO);
|
|
|
|
|
+ close(fildes[0]);
|
|
|
|
|
+ fildes[0] = STDIN_FILENO;
|
|
|
|
|
+ }
|
|
|
|
|
+ close(fildes[1]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ execvp(argv[0], (char* const*)argv);
|
|
|
|
|
+ // exec returned error
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Parent
|
|
|
|
|
+ if (flags & ProcessFlags::STDOUT_PIPE)
|
|
|
|
|
+ {
|
|
|
|
|
+ priv->file = fdopen(fildes[0], "r");
|
|
|
|
|
+ close(fildes[1]);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (flags & ProcessFlags::STDIN_PIPE)
|
|
|
|
|
+ {
|
|
|
|
|
+ priv->file = fdopen(fildes[1], "w");
|
|
|
|
|
+ close(fildes[0]);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ priv->file = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ priv->pid = pid;
|
|
|
|
|
+ return 0;
|
|
|
|
|
+#elif CROWN_PLATFORM_WINDOWS
|
|
|
TempAllocator512 ta;
|
|
TempAllocator512 ta;
|
|
|
StringStream path(ta);
|
|
StringStream path(ta);
|
|
|
|
|
|
|
|
- path << argv[0];
|
|
|
|
|
- path << ' ';
|
|
|
|
|
-#if CROWN_PLATFORM_POSIX
|
|
|
|
|
- path << "2>&1 ";
|
|
|
|
|
-#endif
|
|
|
|
|
- for (s32 i = 1; argv[i] != NULL; ++i)
|
|
|
|
|
|
|
+ for (s32 i = 0; argv[i] != NULL; ++i)
|
|
|
{
|
|
{
|
|
|
const char* arg = argv[i];
|
|
const char* arg = argv[i];
|
|
|
for (; *arg; ++arg)
|
|
for (; *arg; ++arg)
|
|
@@ -78,11 +146,7 @@ s32 Process::spawn(const char* const* argv)
|
|
|
}
|
|
}
|
|
|
path << ' ';
|
|
path << ' ';
|
|
|
}
|
|
}
|
|
|
-#if CROWN_PLATFORM_POSIX
|
|
|
|
|
- priv->file = popen(string_stream::c_str(path), "r");
|
|
|
|
|
|
|
|
|
|
- return priv->file != NULL ? 0 : -1;
|
|
|
|
|
-#elif CROWN_PLATFORM_WINDOWS
|
|
|
|
|
STARTUPINFO info;
|
|
STARTUPINFO info;
|
|
|
memset(&info, 0, sizeof(info));
|
|
memset(&info, 0, sizeof(info));
|
|
|
info.cb = sizeof(info);
|
|
info.cb = sizeof(info);
|
|
@@ -102,22 +166,49 @@ s32 Process::spawn(const char* const* argv)
|
|
|
#endif
|
|
#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-s32 Process::wait(StringStream* output)
|
|
|
|
|
|
|
+bool Process::spawned()
|
|
|
|
|
+{
|
|
|
|
|
+ Private* priv = (Private*)_data;
|
|
|
|
|
+#if CROWN_PLATFORM_POSIX
|
|
|
|
|
+ return priv->pid != -1;
|
|
|
|
|
+#elif CROWN_PLATFORM_WINDOWS
|
|
|
|
|
+ return priv->process.hProcess != 0;
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Process::force_exit()
|
|
|
|
|
+{
|
|
|
|
|
+ Private* priv = (Private*)_data;
|
|
|
|
|
+ CE_ENSURE(process_internal::is_open(priv) == true);
|
|
|
|
|
+#if CROWN_PLATFORM_POSIX
|
|
|
|
|
+ kill(priv->pid, SIGKILL);
|
|
|
|
|
+#elif CROWN_PLATFORM_WINDOWS
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+s32 Process::wait()
|
|
|
{
|
|
{
|
|
|
Private* priv = (Private*)_data;
|
|
Private* priv = (Private*)_data;
|
|
|
CE_ENSURE(process_internal::is_open(priv) == true);
|
|
CE_ENSURE(process_internal::is_open(priv) == true);
|
|
|
|
|
|
|
|
#if CROWN_PLATFORM_POSIX
|
|
#if CROWN_PLATFORM_POSIX
|
|
|
- if (output != NULL)
|
|
|
|
|
|
|
+ pid_t pid;
|
|
|
|
|
+ int wstatus;
|
|
|
|
|
+
|
|
|
|
|
+ if (priv->file != NULL)
|
|
|
{
|
|
{
|
|
|
- char buf[1024];
|
|
|
|
|
- while (fgets(buf, sizeof(buf), priv->file) != NULL)
|
|
|
|
|
- *output << buf;
|
|
|
|
|
|
|
+ fclose(priv->file);
|
|
|
|
|
+ priv->file = NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- s32 exitcode = pclose(priv->file);
|
|
|
|
|
- priv->file = NULL;
|
|
|
|
|
- return exitcode;
|
|
|
|
|
|
|
+ do
|
|
|
|
|
+ {
|
|
|
|
|
+ pid = waitpid(priv->pid, &wstatus, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ while (pid == -1 && errno == EINTR);
|
|
|
|
|
+
|
|
|
|
|
+ priv->pid = -1;
|
|
|
|
|
+ return WIFEXITED(wstatus) ? (s32)WEXITSTATUS(wstatus) : -1;
|
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
#elif CROWN_PLATFORM_WINDOWS
|
|
|
DWORD exitcode = 1;
|
|
DWORD exitcode = 1;
|
|
|
::WaitForSingleObject(priv->process.hProcess, INFINITE);
|
|
::WaitForSingleObject(priv->process.hProcess, INFINITE);
|
|
@@ -129,4 +220,25 @@ s32 Process::wait(StringStream* output)
|
|
|
#endif
|
|
#endif
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+char* Process::fgets(char* data, u32 len)
|
|
|
|
|
+{
|
|
|
|
|
+ Private* priv = (Private*)_data;
|
|
|
|
|
+ CE_ENSURE(process_internal::is_open(priv) == true);
|
|
|
|
|
+#if CROWN_PLATFORM_POSIX
|
|
|
|
|
+ CE_ENSURE(priv->file != NULL);
|
|
|
|
|
+ char* ret = ::fgets(data, len, priv->file);
|
|
|
|
|
+ if (ret == NULL)
|
|
|
|
|
+ {
|
|
|
|
|
+#if 0
|
|
|
|
|
+ if (feof(priv->file))
|
|
|
|
|
+ printf("EOF\n");
|
|
|
|
|
+ else
|
|
|
|
|
+ printf("Error\n");
|
|
|
|
|
+#endif
|
|
|
|
|
+ }
|
|
|
|
|
+ return ret;
|
|
|
|
|
+#elif CROWN_PLATFORM_WINDOWS
|
|
|
|
|
+#endif
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
} // namespace crown
|
|
} // namespace crown
|