summaryrefslogtreecommitdiff
path: root/src/execute.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/execute.cc')
-rw-r--r--src/execute.cc206
1 files changed, 201 insertions, 5 deletions
diff --git a/src/execute.cc b/src/execute.cc
index cbae899..3d8fe62 100644
--- a/src/execute.cc
+++ b/src/execute.cc
@@ -5,12 +5,22 @@
#include "ctor.h"
-#include <unistd.h>
-#include <cstring>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <spawn.h>
+#if !defined(_WIN32)
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <spawn.h>
+#else
+ #define WINDOWS_LEAN_AND_MEAN
+ #include <windows.h>
+ #undef max
+#endif
+
#include <iostream>
+#include <cstring>
+#include <vector>
+#include <deque>
+#include <filesystem>
/*
https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/
@@ -22,6 +32,7 @@ https://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-
namespace
{
+/*
class Env
: public std::vector<char*>
{
@@ -30,7 +41,27 @@ public:
{
for(const auto& arg : args)
{
+ string_data.push_back(arg);
+ push_back(string_data.back().data());
+ }
+ }
+
+ std::deque<std::string> string_data;
+};
+*/
+class Env
+ : public std::vector<char*>
+{
+public:
+ Env(const std::vector<std::string>& args)
+ {
+ for(const auto& arg : args)
+ {
+#if !defined(_WIN32)
push_back(strdup(arg.data()));
+#else
+ push_back(_strdup(arg.data()));
+#endif
}
push_back(nullptr);
}
@@ -44,6 +75,7 @@ public:
}
};
+#if !defined(_WIN32)
int parent_waitpid(pid_t pid)
{
int status{};
@@ -55,6 +87,7 @@ int parent_waitpid(pid_t pid)
return WEXITSTATUS(status);
}
+#endif //_WIN32
} // namespace ::
extern char **environ; // see 'man environ'
@@ -92,6 +125,8 @@ int execute(const ctor::settings& settings,
std::cout << cmd << std::endl;
}
+#if !defined(_WIN32)
+
#if 1
auto pid = vfork();
if(pid == 0)
@@ -133,5 +168,166 @@ int execute(const ctor::settings& settings,
return system(cmd.data());
#endif
+#else // _WIN32
+ std::map<std::string, std::string> new_env;
+ {
+ auto env_strings = GetEnvironmentStrings();
+ const char* ptr = env_strings;
+ std::string key;
+ std::string value;
+ bool key_state{true};
+ while(true)
+ {
+ if(key_state) // searching for key
+ {
+ if(*ptr == '\0')
+ {
+ break;
+ }
+
+ if(*ptr != '=')
+ {
+ key += *ptr;
+ }
+ else
+ {
+ key_state = false;
+ }
+ }
+ else
+ {
+ if(*ptr != '\0')
+ {
+ value += *ptr;
+ }
+ else
+ {
+ new_env.insert({key, value});
+ key = {};
+ value = {};
+ key_state = true;
+ }
+ }
+ ++ptr;
+ }
+ FreeEnvironmentStrings(env_strings);
+ }
+
+ // add new env vars (if any)
+ for(const auto& [key, value] : env)
+ {
+ //if(key == "CL" || key == "LINK" || key == "LIB")
+ {
+ new_env[key] = value;
+ }
+ }
+
+ std::string env_str;
+ for(const auto& [k,v] : new_env)
+ {
+ env_str += k + "=" + v;
+ env_str += '\0';
+ }
+ env_str += '\0';
+
+ STARTUPINFO si{};
+// si.hStdInput = GetStdHandle(((DWORD)-10)/*STD_INPUT_HANDLE*/);
+// si.hStdOutput = GetStdHandle(((DWORD)-11)/*STD_OUTPUT_HANDLE*/);
+// si.hStdError = GetStdHandle(((DWORD)-12)/*STD_ERROR_HANDLE*/);
+// si.dwFlags = /*STARTF_USESTDHANDLES*/0x00000100;
+
+ PROCESS_INFORMATION pi{};
+
+ si.cb = sizeof(si);
+
+ // TODO: Use SetDllDirectory(...) to set DLL search directory
+
+ if(terminate)
+ {
+ char tmpdir[MAX_PATH+1];
+ int cnt{0};
+
+ // The returned string ends with a backslash
+ if(GetTempPathA(sizeof(tmpdir), tmpdir) == 0)
+ {
+ std::cerr << "Could not read TMP folder\n";
+ return GetLastError();
+ }
+
+ char source[MAX_PATH];
+ HMODULE module = GetModuleHandle(0);
+ GetModuleFileNameA(module, source, MAX_PATH);
+
+ while(true)
+ {
+ if(cnt > 10) // If we need to try more than 10 times something is wrong
+ {
+ return 1;
+ }
+
+ std::filesystem::path tmp_file = settings.builddir;
+ tmp_file /= "tmp";
+ std::string target = tmp_file.string() + "-" + std::to_string(cnt);
+ std::cout << "move " << source << " => " << target <<std::endl;
+ if(MoveFileA(source, target.data()))
+ {
+ break; // success
+ }
+
+ auto err = GetLastError();
+ if(err == ERROR_ALREADY_EXISTS)
+ {
+ if(DeleteFileA(target.data()))
+ {
+ continue; // Try again
+ }
+
+ err = GetLastError();
+ if(err != ERROR_ACCESS_DENIED)
+ {
+ std::cerr << "Could not delete file\n";
+ return err;
+ }
+
+ cnt++;
+ continue; // Increment and try again
+ }
+ else
+ {
+ std::cerr << "Could not move file\n";
+ return err;
+ }
+ }
+ }
+
+ if(!CreateProcess(nullptr, // lpApplicationName
+ (char*)cmd.data(), // lpCommandLine
+ nullptr, // lpProcessAttributes
+ nullptr, // lpThreadAttributes
+ TRUE, // bInheritHandles
+ INHERIT_PARENT_AFFINITY |
+ //DETACHED_PROCESS |
+ ///*DEBUG_PROCESS*/ 0x00000001 |
+ ///*CREATE_NO_WINDOW*/ 0x08000000 |
+ ///*CREATE_BREAKAWAY_FROM_JOB*/ 0x01000000 |
+ /*CREATE_NEW_PROCESS_GROUP*/ 0x00000200 |
+ 0, // dwCreationFlags
+ env_str.data(), // lpEnvironment
+ nullptr, // lpCurrentDirectory
+ &si, // lpStartupInfo
+ &pi)) // lpProcessInformation
+ {
+ return 1; // Could not start process;
+ }
+
+ // Now 'pi.hProcess' contains the process HANDLE, which you can use to
+ // wait for it like this:
+ const DWORD infinite = 0xFFFFFFFF;
+ WaitForSingleObject(pi.hProcess, infinite);
+ DWORD exitCode{0};
+ GetExitCodeProcess(pi.hProcess, &exitCode);
+ return exitCode;
+#endif // _WIN32
+
return 1;
}