Get process betterGet shell somewhat working
This commit is contained in:
@ -19,6 +19,7 @@ src/Mail/Smtp.cpp
|
|||||||
src/Serialization/Json.cpp
|
src/Serialization/Json.cpp
|
||||||
src/Serialization/SQLite.cpp
|
src/Serialization/SQLite.cpp
|
||||||
src/Platform/Environment.cpp
|
src/Platform/Environment.cpp
|
||||||
|
src/Platform/Process.cpp
|
||||||
src/Streams/FileStream.cpp
|
src/Streams/FileStream.cpp
|
||||||
src/Streams/MemoryStream.cpp
|
src/Streams/MemoryStream.cpp
|
||||||
src/Streams/NetworkStream.cpp
|
src/Streams/NetworkStream.cpp
|
||||||
@ -394,6 +395,9 @@ install(TARGETS tjsonunpretty DESTINATION bin)
|
|||||||
add_executable(ttime apps/ttime.cpp)
|
add_executable(ttime apps/ttime.cpp)
|
||||||
target_link_libraries(ttime PUBLIC tessesframework)
|
target_link_libraries(ttime PUBLIC tessesframework)
|
||||||
install(TARGETS ttime DESTINATION bin)
|
install(TARGETS ttime DESTINATION bin)
|
||||||
|
add_executable(tshell apps/tshell.cpp)
|
||||||
|
target_link_libraries(tshell PUBLIC tessesframework)
|
||||||
|
install(TARGETS tshell DESTINATION bin)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(InstallRequiredSystemLibraries)
|
include(InstallRequiredSystemLibraries)
|
||||||
|
|||||||
@ -41,7 +41,8 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_C_COMPILER": "cl.exe",
|
"CMAKE_C_COMPILER": "cl.exe",
|
||||||
"CMAKE_CXX_COMPILER": "cl.exe",
|
"CMAKE_CXX_COMPILER": "cl.exe",
|
||||||
"TESSESFRAMEWORK_FETCHCONTENT": true
|
"TESSESFRAMEWORK_ENABLE_MBED": false,
|
||||||
|
"TESSESFRAMEWORK_FETCHCONTENT": false
|
||||||
},
|
},
|
||||||
"condition": {
|
"condition": {
|
||||||
"type": "equals",
|
"type": "equals",
|
||||||
|
|||||||
127
apps/tshell.cpp
Normal file
127
apps/tshell.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#include "TessesFramework/TessesFramework.hpp"
|
||||||
|
#include "TessesFramework/Platform/Process.hpp"
|
||||||
|
using namespace Tesses::Framework;
|
||||||
|
using namespace Tesses::Framework::Platform;
|
||||||
|
using namespace Tesses::Framework::TextStreams;
|
||||||
|
using namespace Tesses::Framework::Filesystem;
|
||||||
|
|
||||||
|
void split_command(std::string cmd, std::vector<std::string>& args)
|
||||||
|
{
|
||||||
|
bool inStr=false;
|
||||||
|
std::string cur={};
|
||||||
|
auto flush=[&]()->void {
|
||||||
|
if(cur.empty()) return;
|
||||||
|
args.push_back(cur);
|
||||||
|
cur={};
|
||||||
|
};
|
||||||
|
for(size_t i = 0; i < cmd.size(); i++)
|
||||||
|
{
|
||||||
|
if(inStr)
|
||||||
|
{
|
||||||
|
if(cmd[i] == '\"') inStr=false;
|
||||||
|
else if(cmd[i] == '\\')
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if(i < cmd.size())
|
||||||
|
{
|
||||||
|
cmd.push_back(cmd[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else cur.push_back(cmd[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(cmd[i] == ' ') flush();
|
||||||
|
else if(cmd[i] == '\"') {
|
||||||
|
inStr=true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cur.push_back(cmd[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc,char** argv)
|
||||||
|
{
|
||||||
|
TF_Init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
std::cout << VFSPath::GetAbsoluteCurrentDirectory().ToString() << "$ ";
|
||||||
|
|
||||||
|
|
||||||
|
std::string text;
|
||||||
|
StdIn().ReadLine(text);
|
||||||
|
std::vector<std::string> args;
|
||||||
|
split_command(text,args);
|
||||||
|
if(args.empty()) continue;
|
||||||
|
if(args[0] == "exit") break;
|
||||||
|
else if(args[0] == "echo") { if(args.size() > 1) std::cout << args[1] << std::endl;}
|
||||||
|
else if(args[0] == "cd") {
|
||||||
|
if(args.size() < 2)
|
||||||
|
{
|
||||||
|
VFSPath::SetAbsoluteCurrentDirectory(Environment::SpecialFolders::GetHomeFolder());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
VFSPath::SetAbsoluteCurrentDirectory(args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(args[0] == "printargs")
|
||||||
|
{
|
||||||
|
for(size_t i = 1; i < args.size(); i++)
|
||||||
|
{
|
||||||
|
std::cout << "\"" << Http::HttpUtils::Replace(args[i],"\"","\\\"") << "\"" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args[0] == "sigtermtest")
|
||||||
|
{
|
||||||
|
if (args.size() < 2) continue;
|
||||||
|
std::vector<std::string> args2(args.begin() + 1, args.end());
|
||||||
|
|
||||||
|
auto path = Environment::GetRealExecutablePath(args2[0]);
|
||||||
|
Platform::Process p(path.ToString(), args2);
|
||||||
|
if (p.Start())
|
||||||
|
{
|
||||||
|
std::cout << "Press enter to sigterm" << std::endl;
|
||||||
|
StdIn().ReadLine();
|
||||||
|
p.Kill(SIGTERM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(args[0] == "rstdi")
|
||||||
|
{
|
||||||
|
if(args.size()<3) continue;
|
||||||
|
std::vector<std::string> args2(args.begin()+2,args.end());
|
||||||
|
auto f = LocalFS.OpenFile(args[1],"rb");
|
||||||
|
if(f != nullptr)
|
||||||
|
{
|
||||||
|
auto path = Environment::GetRealExecutablePath(args2[0]);
|
||||||
|
Platform::Process p(path.ToString(),args2);
|
||||||
|
p.redirectStdIn=true;
|
||||||
|
if(p.Start())
|
||||||
|
{
|
||||||
|
auto strm = p.GetStdinStream();
|
||||||
|
f->CopyTo(strm);
|
||||||
|
delete strm;
|
||||||
|
p.CloseStdInNow();
|
||||||
|
p.WaitForExit();
|
||||||
|
}
|
||||||
|
delete f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto path = Environment::GetRealExecutablePath(args[0]);
|
||||||
|
Platform::Process p(path.ToString(),args);
|
||||||
|
if (p.Start())
|
||||||
|
p.WaitForExit();
|
||||||
|
else
|
||||||
|
std::cout << "Failed To Run Process: " << path.ToString() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TF_Quit();
|
||||||
|
}
|
||||||
@ -1,12 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "TessesFramework/Streams/Stream.hpp"
|
#include "TessesFramework/Streams/Stream.hpp"
|
||||||
#include "TessesFramework/HiddenField.hpp"
|
#include "TessesFramework/HiddenField.hpp"
|
||||||
|
#include <signal.h>
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define SIGKILL 9
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Tesses::Framework::Platform {
|
namespace Tesses::Framework::Platform {
|
||||||
class Process {
|
class Process {
|
||||||
private:
|
private:
|
||||||
HiddenField hidden;
|
HiddenField hidden;
|
||||||
|
bool exited = false;
|
||||||
|
int exitCode=0;
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
@ -16,6 +23,8 @@ class Process {
|
|||||||
bool redirectStdIn=false;
|
bool redirectStdIn=false;
|
||||||
bool redirectStdOut=false;
|
bool redirectStdOut=false;
|
||||||
bool redirectStdErr=false;
|
bool redirectStdErr=false;
|
||||||
|
bool HasExited();
|
||||||
|
|
||||||
|
|
||||||
void CloseStdInNow();
|
void CloseStdInNow();
|
||||||
//YOU ARE RESPONSABLE FOR FREEING THIS STREAM OBJECT
|
//YOU ARE RESPONSABLE FOR FREEING THIS STREAM OBJECT
|
||||||
|
|||||||
@ -35,6 +35,8 @@
|
|||||||
#include "Serialization/Json.hpp"
|
#include "Serialization/Json.hpp"
|
||||||
#include "Serialization/SQLite.hpp"
|
#include "Serialization/SQLite.hpp"
|
||||||
#include "Platform/Environment.hpp"
|
#include "Platform/Environment.hpp"
|
||||||
|
#include "Platform/Process.hpp"
|
||||||
|
#include "Text/StringConverter.hpp"
|
||||||
#include "SDL2/FontCache.hpp"
|
#include "SDL2/FontCache.hpp"
|
||||||
#include "SDL2/Stream.hpp"
|
#include "SDL2/Stream.hpp"
|
||||||
#include "SDL2/GUI.hpp"
|
#include "SDL2/GUI.hpp"
|
||||||
|
|||||||
@ -208,6 +208,7 @@ namespace Tesses::Framework::Filesystem
|
|||||||
}
|
}
|
||||||
VFSPath VFSPath::MakeAbsolute(VFSPath curDir)
|
VFSPath VFSPath::MakeAbsolute(VFSPath curDir)
|
||||||
{
|
{
|
||||||
|
if (!this->relative) return *this;
|
||||||
VFSPath p2 = curDir / *this;
|
VFSPath p2 = curDir / *this;
|
||||||
return p2.CollapseRelativeParents();
|
return p2.CollapseRelativeParents();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "TessesFramework/Filesystem/VFSFix.hpp"
|
#include "TessesFramework/Filesystem/VFSFix.hpp"
|
||||||
#include "TessesFramework/Text/StringConverter.hpp"
|
#include "TessesFramework/Text/StringConverter.hpp"
|
||||||
|
|
||||||
using namespace Tesses::Framework::Text::StringConverter;
|
using namespace Tesses::Framework::Text::StringConverter;
|
||||||
#endif
|
#endif
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
@ -120,8 +121,9 @@ namespace Tesses::Framework::Platform::Environment
|
|||||||
VFSPath GetRealExecutablePath(VFSPath realPath)
|
VFSPath GetRealExecutablePath(VFSPath realPath)
|
||||||
{
|
{
|
||||||
using namespace Tesses::Framework::Http;
|
using namespace Tesses::Framework::Http;
|
||||||
|
|
||||||
|
|
||||||
if(!realPath.relative) return realPath.MakeAbsolute();
|
if(!realPath.relative) return realPath;
|
||||||
if(LocalFS.FileExists(realPath)) return realPath.MakeAbsolute();
|
if(LocalFS.FileExists(realPath)) return realPath.MakeAbsolute();
|
||||||
const char* path = std::getenv("PATH");
|
const char* path = std::getenv("PATH");
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -216,9 +218,9 @@ namespace Tesses::Framework::Platform::Environment
|
|||||||
}
|
}
|
||||||
FreeEnvironmentStringsW(environ0);
|
FreeEnvironmentStringsW(environ0);
|
||||||
#else
|
#else
|
||||||
for(char** envthing = environ; envthing != NULL; envthing++)
|
for(char** envthing = environ; *envthing != NULL; envthing++)
|
||||||
{
|
{
|
||||||
|
//if(*envthing == NULL) break;
|
||||||
auto items = Http::HttpUtils::SplitString(*envthing,"=",2);
|
auto items = Http::HttpUtils::SplitString(*envthing,"=",2);
|
||||||
if(items.size() == 2)
|
if(items.size() == 2)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "TessesFramework/Platform/Process.hpp"
|
#include "TessesFramework/Platform/Process.hpp"
|
||||||
#include "TessesFramework/Http/HttpUtils.hpp"
|
#include "TessesFramework/Http/HttpUtils.hpp"
|
||||||
#include "TessesFramework/Platform/Environment.hpp"
|
#include "TessesFramework/Platform/Environment.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -8,7 +9,7 @@ extern "C" {
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
}
|
}
|
||||||
#include "TessesFramework/Filesystem/VFSFix.hpp"
|
#include "TessesFramework/Filesystem/VFSFix.hpp"
|
||||||
#include 'TessesFramework/Text/StringConverter.hpp'
|
#include "TessesFramework/Text/StringConverter.hpp"
|
||||||
using namespace Tesses::Framework::Text::StringConverter;
|
using namespace Tesses::Framework::Text::StringConverter;
|
||||||
static void escape_windows_args(std::string& str, std::vector<std::string> args)
|
static void escape_windows_args(std::string& str, std::vector<std::string> args)
|
||||||
{
|
{
|
||||||
@ -38,7 +39,6 @@ static void escape_windows_args(std::string& str, std::vector<std::string> args)
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
|
||||||
@ -48,16 +48,30 @@ static void escape_windows_args(std::string& str, std::vector<std::string> args)
|
|||||||
|
|
||||||
namespace Tesses::Framework::Platform {
|
namespace Tesses::Framework::Platform {
|
||||||
|
|
||||||
class ProcessData {
|
class ProcessData : public HiddenFieldData {
|
||||||
public:
|
public:
|
||||||
//TODO: Implement for WIN32
|
//TODO: Implement for WIN32
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
STARTUPINFO si;
|
STARTUPINFOW si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
|
|
||||||
HANDLE stdin_strm;
|
HANDLE stdin_strm;
|
||||||
HANDLE stdout_strm;
|
HANDLE stdout_strm;
|
||||||
HANDLE stderr_strm;
|
HANDLE stderr_strm;
|
||||||
|
|
||||||
|
static int __stdcall KillGraceFully(HWND hndle, LPARAM arg)
|
||||||
|
{
|
||||||
|
auto pd=static_cast<ProcessData*>((void*)arg);
|
||||||
|
DWORD curProc;
|
||||||
|
GetWindowThreadProcessId(hndle, &curProc);
|
||||||
|
if (curProc == pd->pi.dwProcessId)
|
||||||
|
{
|
||||||
|
PostMessage(hndle, WM_CLOSE, 0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
@ -67,6 +81,8 @@ namespace Tesses::Framework::Platform {
|
|||||||
int stderr_strm;
|
int stderr_strm;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
ProcessData() {
|
ProcessData() {
|
||||||
//TODO: Implement for WIN32
|
//TODO: Implement for WIN32
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -90,7 +106,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
HANDLE strm;
|
HANDLE strm;
|
||||||
bool writing;
|
bool writing;
|
||||||
bool eos;
|
bool eos;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
#else
|
#else
|
||||||
int strm;
|
int strm;
|
||||||
|
|
||||||
@ -105,7 +121,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
this->writing = writing;
|
this->writing = writing;
|
||||||
this->eos = false;
|
this->eos = false;
|
||||||
}
|
}
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
#else
|
#else
|
||||||
ProcessStream(int strm, bool writing)
|
ProcessStream(int strm, bool writing)
|
||||||
{
|
{
|
||||||
@ -119,7 +135,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
//TODO: Implement for WIN32
|
//TODO: Implement for WIN32
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return this->strm == NULL || eos;
|
return this->strm == NULL || eos;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return this->strm < 0 || eos;
|
return this->strm < 0 || eos;
|
||||||
@ -130,7 +146,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
//TODO: Implement for WIN32
|
//TODO: Implement for WIN32
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
return !writing && this->strm != NULL;
|
return !writing && this->strm != NULL;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
return !writing && this->strm > -1;
|
return !writing && this->strm > -1;
|
||||||
@ -142,7 +158,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
return writing && this->strm != NULL;
|
return writing && this->strm != NULL;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
return writing && this->strm > -1;
|
return writing && this->strm > -1;
|
||||||
@ -161,8 +177,8 @@ namespace Tesses::Framework::Platform {
|
|||||||
if (dataR == 0) {
|
if (dataR == 0) {
|
||||||
this->eos = true;
|
this->eos = true;
|
||||||
}
|
}
|
||||||
return (size_t)dataW;
|
return (size_t)dataR;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
if(this->strm < 0 || this->eos && writing) return 0;
|
if(this->strm < 0 || this->eos && writing) return 0;
|
||||||
@ -184,7 +200,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (size_t)dataW;
|
return (size_t)dataW;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
if(this->strm < 0 || !writing) return 0;
|
if(this->strm < 0 || !writing) return 0;
|
||||||
@ -213,6 +229,31 @@ namespace Tesses::Framework::Platform {
|
|||||||
this->includeThisEnv = includeThisEnv;
|
this->includeThisEnv = includeThisEnv;
|
||||||
this->hidden.AllocField<ProcessData>();
|
this->hidden.AllocField<ProcessData>();
|
||||||
}
|
}
|
||||||
|
bool Process::HasExited()
|
||||||
|
{
|
||||||
|
if (this->exited) return true;
|
||||||
|
ProcessData* p = this->hidden.GetField<ProcessData*>();
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (WaitForSingleObject(p->pi.hProcess, 0) == WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
DWORD ec = 0;
|
||||||
|
GetExitCodeProcess(p->pi.hProcess,&ec);
|
||||||
|
this->exitCode = (int)ec;
|
||||||
|
this->exited = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
int r;
|
||||||
|
if (waitpid(this->hidden.GetField<ProcessData*>()->pid, &r, WNOHANG) != -1)
|
||||||
|
{
|
||||||
|
this->exited = true;
|
||||||
|
this->exitCode = r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Process::Process(std::string name, std::vector<std::string> args, std::vector<std::string> env,bool includeThisEnv) : Process(name,args,std::vector<std::pair<std::string,std::string>>(),includeThisEnv)
|
Process::Process(std::string name, std::vector<std::string> args, std::vector<std::string> env,bool includeThisEnv) : Process(name,args,std::vector<std::pair<std::string,std::string>>(),includeThisEnv)
|
||||||
{
|
{
|
||||||
this->env.resize(env.size());
|
this->env.resize(env.size());
|
||||||
@ -232,11 +273,35 @@ namespace Tesses::Framework::Platform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void Process::CloseStdInNow()
|
||||||
|
{
|
||||||
|
ProcessData* p = this->hidden.GetField<ProcessData*>();
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
if (p->stdin_strm != NULL)
|
||||||
|
{
|
||||||
|
CloseHandle(p->stdin_strm);
|
||||||
|
p->stdin_strm = NULL;
|
||||||
|
}
|
||||||
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (p->stdin_strm > -1)
|
||||||
|
{
|
||||||
|
close(p->stdin_strm);
|
||||||
|
p->stdin_strm = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
Process::~Process()
|
Process::~Process()
|
||||||
{
|
{
|
||||||
|
|
||||||
ProcessData* p = this->hidden.GetField<ProcessData*>();
|
ProcessData* p = this->hidden.GetField<ProcessData*>();
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
if(!this->exited)
|
||||||
|
Kill(SIGTERM);
|
||||||
if (p->stdin_strm != NULL)
|
if (p->stdin_strm != NULL)
|
||||||
CloseHandle(p->stdin_strm);
|
CloseHandle(p->stdin_strm);
|
||||||
|
|
||||||
@ -245,9 +310,25 @@ namespace Tesses::Framework::Platform {
|
|||||||
|
|
||||||
if (p->stderr_strm != NULL)
|
if (p->stderr_strm != NULL)
|
||||||
CloseHandle(p->stderr_strm);
|
CloseHandle(p->stderr_strm);
|
||||||
|
|
||||||
|
|
||||||
CloseHandle(p->pi.hProcess);
|
CloseHandle(p->pi.hProcess);
|
||||||
CloseHandle(p->pi.hThread);
|
CloseHandle(p->pi.hThread);
|
||||||
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
if (!this->exited)
|
||||||
|
{
|
||||||
|
Kill(SIGTERM);
|
||||||
|
WaitForExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p->stdin_strm != -1)
|
||||||
|
close(p->stdin_strm);
|
||||||
|
if (p->stdout_strm != -1)
|
||||||
|
close(p->stdout_strm);
|
||||||
|
if (p->stderr_strm != -1)
|
||||||
|
close(p->stderr_strm);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +339,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
ProcessData* p =
|
ProcessData* p =
|
||||||
this->hidden.GetField<ProcessData*>();
|
this->hidden.GetField<ProcessData*>();
|
||||||
std::vector<std::pair<std::string,std::string>> envs;
|
std::vector<std::pair<std::string,std::string>> envs;
|
||||||
|
|
||||||
if(this->includeThisEnv)
|
if(this->includeThisEnv)
|
||||||
Environment::GetEnvironmentVariables(envs);
|
Environment::GetEnvironmentVariables(envs);
|
||||||
|
|
||||||
@ -269,6 +350,7 @@ namespace Tesses::Framework::Platform {
|
|||||||
{
|
{
|
||||||
if(item.first == itemNew.first)
|
if(item.first == itemNew.first)
|
||||||
{
|
{
|
||||||
|
|
||||||
item.second = itemNew.second;
|
item.second = itemNew.second;
|
||||||
has=true;
|
has=true;
|
||||||
break;
|
break;
|
||||||
@ -278,6 +360,11 @@ namespace Tesses::Framework::Platform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
|
||||||
|
ZeroMemory(&p->si, sizeof(p->si));
|
||||||
|
p->si.cb = sizeof(p->si);
|
||||||
|
ZeroMemory(&p->pi, sizeof(p->pi));
|
||||||
std::u16string u16_name;
|
std::u16string u16_name;
|
||||||
std::u16string u16_args;
|
std::u16string u16_args;
|
||||||
std::string args;
|
std::string args;
|
||||||
@ -306,66 +393,89 @@ namespace Tesses::Framework::Platform {
|
|||||||
attr.nLength = sizeof(attr);
|
attr.nLength = sizeof(attr);
|
||||||
attr.lpSecurityDescriptor = NULL;
|
attr.lpSecurityDescriptor = NULL;
|
||||||
attr.bInheritHandle = true;
|
attr.bInheritHandle = true;
|
||||||
p->si->hStdInput = NULL;
|
p->si.hStdInput = NULL;
|
||||||
p->si->hStdOutput = NULL;
|
p->si.hStdOutput = NULL;
|
||||||
|
|
||||||
p->si->hStdError = NULL;
|
p->si.hStdError = NULL;
|
||||||
|
|
||||||
p->stdin_strm = NULL;
|
p->stdin_strm = NULL;
|
||||||
p->stdout_strm = NULL;
|
p->stdout_strm = NULL;
|
||||||
p->stderr_strm = NULL;
|
p->stderr_strm = NULL;
|
||||||
|
if (this->redirectStdIn || this->redirectStdOut || this->redirectStdErr)
|
||||||
|
{
|
||||||
|
p->si.dwFlags |= STARTF_USESTDHANDLES;
|
||||||
|
if (!this->redirectStdIn)
|
||||||
|
{
|
||||||
|
p->si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
}
|
||||||
|
if (!this->redirectStdOut)
|
||||||
|
{
|
||||||
|
|
||||||
|
p->si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
}
|
||||||
|
if (!this->redirectStdOut)
|
||||||
|
{
|
||||||
|
p->si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this->redirectStdIn)
|
if (this->redirectStdIn)
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&p->si->hStdInput, &p->stdin_strm, &attr,0)) return false;
|
if (!CreatePipe(&p->si.hStdInput, &p->stdin_strm, &attr,0)) return false;
|
||||||
|
|
||||||
|
SetHandleInformation(p->stdin_strm, HANDLE_FLAG_INHERIT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->redirectStdOut)
|
if (this->redirectStdOut)
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&p->stdout_strm, &p->si->hStdOutput, &attr, 0))
|
if (!CreatePipe(&p->stdout_strm, &p->si.hStdOutput, &attr, 0))
|
||||||
{
|
{
|
||||||
if (this->redirectStdIn)
|
if (this->redirectStdIn)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stdin_strm);
|
CloseHandle(p->stdin_strm);
|
||||||
CloseHandle(p->si->hStdInput);
|
CloseHandle(p->si.hStdInput);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetHandleInformation(p->stdout_strm, HANDLE_FLAG_INHERIT, 0);
|
||||||
}
|
}
|
||||||
if (this->redirectStdErr)
|
if (this->redirectStdErr)
|
||||||
{
|
{
|
||||||
if (!CreatePipe(&p->stderr_strm, &p->si->hStdError, &attr, 0))
|
if (!CreatePipe(&p->stderr_strm, &p->si.hStdError, &attr, 0))
|
||||||
{
|
{
|
||||||
if (this->redirectStdIn)
|
if (this->redirectStdIn)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stdin_strm);
|
CloseHandle(p->stdin_strm);
|
||||||
CloseHandle(p->si->hStdInput);
|
CloseHandle(p->si.hStdInput);
|
||||||
}
|
}
|
||||||
if (this->redirectStdOut)
|
if (this->redirectStdOut)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stdout_strm);
|
CloseHandle(p->stdout_strm);
|
||||||
CloseHandle(p->si->hStdOutput);
|
CloseHandle(p->si.hStdOutput);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetHandleInformation(p->stderr_strm, HANDLE_FLAG_INHERIT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CreateProcessW(u16_name.c_str(), u16_args.data(), NULL, NULL, (this->redirectStdIn || this->redirectStdOut || this->redirectStdErr), CREATE_UNICODE_ENVIRONMENT, (LPCWSTR)env.c_str(), workDir.empty() ? (LPCWSTR)NULL : (LPCWSTR)workDir.c_str(), &(p->si), &(p->pi)))
|
if (!CreateProcessW((LPCWSTR)u16_name.c_str(), (LPWSTR)u16_args.data(), NULL, NULL, (this->redirectStdIn || this->redirectStdOut || this->redirectStdErr), CREATE_UNICODE_ENVIRONMENT, (LPVOID)env.c_str(), workDir.empty() ? (LPCWSTR)NULL : (LPCWSTR)workDir.c_str(), &(p->si), &(p->pi)))
|
||||||
{
|
{
|
||||||
if (this->redirectStdIn)
|
if (this->redirectStdIn)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stdin_strm);
|
CloseHandle(p->stdin_strm);
|
||||||
CloseHandle(p->si->hStdInput);
|
CloseHandle(p->si.hStdInput);
|
||||||
}
|
}
|
||||||
if (this->redirectStdOut)
|
if (this->redirectStdOut)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stdout_strm);
|
CloseHandle(p->stdout_strm);
|
||||||
CloseHandle(p->si->hStdOutput);
|
CloseHandle(p->si.hStdOutput);
|
||||||
}
|
}
|
||||||
if (this->redirectStdErr)
|
if (this->redirectStdErr)
|
||||||
{
|
{
|
||||||
CloseHandle(p->stderr_strm);
|
CloseHandle(p->stderr_strm);
|
||||||
CloseHandle(p->si->hStdError);
|
CloseHandle(p->si.hStdError);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -386,8 +496,8 @@ CreateProcessW(
|
|||||||
_Out_ LPPROCESS_INFORMATION lpProcessInformation
|
_Out_ LPPROCESS_INFORMATION lpProcessInformation
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
return false;
|
return true;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -460,6 +570,7 @@ CreateProcessW(
|
|||||||
std::vector<std::string> env2;
|
std::vector<std::string> env2;
|
||||||
env2.resize(envs.size());
|
env2.resize(envs.size());
|
||||||
|
|
||||||
|
|
||||||
for(size_t i = 0; i < envs.size(); i++)
|
for(size_t i = 0; i < envs.size(); i++)
|
||||||
{
|
{
|
||||||
env2[i] = envs[i].first + "=" + envs[i].second;
|
env2[i] = envs[i].first + "=" + envs[i].second;
|
||||||
@ -468,13 +579,13 @@ CreateProcessW(
|
|||||||
char** argv = new char*[args.size()+1];
|
char** argv = new char*[args.size()+1];
|
||||||
argv[args.size()]=NULL;
|
argv[args.size()]=NULL;
|
||||||
char** envp = new char*[env2.size()+1];
|
char** envp = new char*[env2.size()+1];
|
||||||
envp[env.size()]=NULL;
|
envp[env2.size()]=NULL;
|
||||||
|
|
||||||
for(size_t i = 0; i < args.size();i++)
|
for(size_t i = 0; i < args.size();i++)
|
||||||
{
|
{
|
||||||
argv[i] = (char*)args[i].c_str();
|
argv[i] = (char*)args[i].c_str();
|
||||||
}
|
}
|
||||||
for(size_t i = 0; i < env.size();i++)
|
for(size_t i = 0; i < env2.size();i++)
|
||||||
{
|
{
|
||||||
envp[i] = (char*)env2[i].c_str();
|
envp[i] = (char*)env2[i].c_str();
|
||||||
}
|
}
|
||||||
@ -512,10 +623,31 @@ CreateProcessW(
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Process::Kill(int signal)
|
void Process::Kill(int signal)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
if (signal != SIGKILL && signal != SIGTERM) std::cout << "WARN: We terminated the process" << std::endl;
|
||||||
|
|
||||||
|
if (signal == SIGTERM)
|
||||||
|
{
|
||||||
|
auto win = this->hidden.GetField<ProcessData*>();
|
||||||
|
if (EnumWindows(ProcessData::KillGraceFully, (LPARAM)(void*)win))
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(win->pi.hProcess, 60000) != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
PostThreadMessage(win->pi.dwThreadId, WM_QUIT, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PostThreadMessage(win->pi.dwThreadId, WM_QUIT, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TerminateProcess(this->hidden.GetField<ProcessData*>()->pi.hProcess,-1);
|
||||||
|
|
||||||
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
#else
|
#else
|
||||||
kill(this->hidden.GetField<ProcessData*>()->pid,signal);
|
kill(this->hidden.GetField<ProcessData*>()->pid,signal);
|
||||||
#endif
|
#endif
|
||||||
@ -523,22 +655,34 @@ CreateProcessW(
|
|||||||
|
|
||||||
int Process::WaitForExit()
|
int Process::WaitForExit()
|
||||||
{
|
{
|
||||||
|
if (this->exited) return this->exitCode;
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
auto p = this->hidden.GetField<ProcessData*>();
|
||||||
reutnr -1;
|
WaitForSingleObject(p->pi.hProcess, INFINITE);
|
||||||
|
DWORD ret=0;
|
||||||
|
GetExitCodeProcess(p->pi.hThread, &ret);
|
||||||
|
this->exitCode = (int)ret;
|
||||||
|
this->exited = true;
|
||||||
|
return (int)ret;
|
||||||
|
|
||||||
|
#elif defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
|
return -1;
|
||||||
#else
|
#else
|
||||||
int r;
|
int r;
|
||||||
if(waitpid(this->hidden.GetField<ProcessData*>()->pid,&r,0) != -1)
|
if (waitpid(this->hidden.GetField<ProcessData*>()->pid, &r, 0) != -1)
|
||||||
|
{
|
||||||
|
this->exited = true;
|
||||||
|
this->exitCode = r;
|
||||||
return r;
|
return r;
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Tesses::Framework::Streams::Stream* Process::GetStdinStream()
|
Tesses::Framework::Streams::Stream* Process::GetStdinStream()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
if (this->exited) return nullptr;
|
||||||
return nullptr;
|
#if defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdin_strm,true);
|
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdin_strm,true);
|
||||||
@ -546,9 +690,9 @@ CreateProcessW(
|
|||||||
}
|
}
|
||||||
Tesses::Framework::Streams::Stream* Process::GetStdoutStream()
|
Tesses::Framework::Streams::Stream* Process::GetStdoutStream()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
|
||||||
return nullptr;
|
if (this->exited) return nullptr;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#if defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdout_strm,false);
|
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stdout_strm,false);
|
||||||
@ -556,9 +700,9 @@ CreateProcessW(
|
|||||||
}
|
}
|
||||||
Tesses::Framework::Streams::Stream* Process::GetStderrStream()
|
Tesses::Framework::Streams::Stream* Process::GetStderrStream()
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
|
||||||
return nullptr;
|
if (this->exited) return nullptr;
|
||||||
#elif defined(GEKKO) || defined(__PS2__) defined(__SWITCH__)
|
#if defined(GEKKO) || defined(__PS2__) || defined(__SWITCH__)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stderr_strm,false);
|
return new ProcessStream(this->hidden.GetField<ProcessData*>()->stderr_strm,false);
|
||||||
|
|||||||
@ -132,6 +132,14 @@ namespace Tesses::Framework
|
|||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
MSG winMSG;
|
||||||
|
if (PeekMessage(&winMSG, NULL, WM_QUIT, WM_QUIT, 1))
|
||||||
|
{
|
||||||
|
isRunning = false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
|
#if defined(TESSESFRAMEWORK_ENABLE_SDL2)
|
||||||
Tesses::Framework::SDL2::gui.Update();
|
Tesses::Framework::SDL2::gui.Update();
|
||||||
@ -182,6 +190,8 @@ namespace Tesses::Framework
|
|||||||
tzset();
|
tzset();
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
system(" ");
|
system(" ");
|
||||||
|
signal(SIGINT, _sigInt);
|
||||||
|
signal(SIGTERM, _sigInt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
isRunning=true;
|
isRunning=true;
|
||||||
@ -214,6 +224,7 @@ if (iResult != 0) {
|
|||||||
#else
|
#else
|
||||||
signal(SIGPIPE,SIG_IGN);
|
signal(SIGPIPE,SIG_IGN);
|
||||||
signal(SIGINT,_sigInt);
|
signal(SIGINT,_sigInt);
|
||||||
|
signal(SIGTERM, _sigInt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user