2025-05-02 14:17:47 +02:00
|
|
|
#include "bind_satdump.h"
|
2025-05-02 17:34:36 +02:00
|
|
|
#include <string>
|
2025-05-02 14:17:47 +02:00
|
|
|
|
2025-05-02 18:00:30 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <Windows.h>
|
2025-05-03 14:52:52 +02:00
|
|
|
|
|
|
|
|
#include <TlHelp32.h>
|
2025-05-02 18:00:30 +02:00
|
|
|
#endif
|
|
|
|
|
|
2025-05-02 14:17:47 +02:00
|
|
|
namespace satdump
|
|
|
|
|
{
|
|
|
|
|
namespace script
|
|
|
|
|
{
|
|
|
|
|
// This function calls the system command, captures the stdout and return the status
|
|
|
|
|
// Return of -1 indicates an error. Else the return code is the return status of the executed command
|
|
|
|
|
// ref: https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po
|
|
|
|
|
int ExecSystemCmd(const std::string &str, std::string &out)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
// Convert the command to UTF16 to properly handle unicode path names
|
|
|
|
|
wchar_t bufUTF16[10000];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufUTF16, 10000);
|
|
|
|
|
|
|
|
|
|
// Create a pipe to capture the stdout from the system command
|
|
|
|
|
HANDLE pipeRead, pipeWrite;
|
|
|
|
|
SECURITY_ATTRIBUTES secAttr = {0};
|
|
|
|
|
secAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
|
|
|
secAttr.bInheritHandle = TRUE;
|
|
|
|
|
secAttr.lpSecurityDescriptor = NULL;
|
|
|
|
|
if (!CreatePipe(&pipeRead, &pipeWrite, &secAttr, 0))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
// Start the process for the system command, informing the pipe to
|
|
|
|
|
// capture stdout, and also to skip showing the command window
|
|
|
|
|
STARTUPINFOW si = {0};
|
|
|
|
|
si.cb = sizeof(STARTUPINFOW);
|
|
|
|
|
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
|
|
|
|
si.hStdOutput = pipeWrite;
|
|
|
|
|
si.hStdError = pipeWrite;
|
|
|
|
|
si.wShowWindow = SW_HIDE;
|
|
|
|
|
PROCESS_INFORMATION pi = {0};
|
|
|
|
|
BOOL success = CreateProcessW(NULL, bufUTF16, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(pipeWrite);
|
|
|
|
|
CloseHandle(pipeRead);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the command until the end, while capturing stdout
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
// Wait for a while to allow the process to work
|
|
|
|
|
DWORD ret = WaitForSingleObject(pi.hProcess, 50);
|
|
|
|
|
|
|
|
|
|
// Read from the stdout if there is any data
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
char buf[1024];
|
|
|
|
|
DWORD readCount = 0;
|
|
|
|
|
DWORD availCount = 0;
|
|
|
|
|
|
|
|
|
|
if (!::PeekNamedPipe(pipeRead, NULL, 0, NULL, &availCount, NULL))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (availCount == 0)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!::ReadFile(pipeRead, buf, sizeof(buf) - 1 < availCount ? sizeof(buf) - 1 : availCount, &readCount, NULL) || !readCount)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
buf[readCount] = 0;
|
|
|
|
|
out += buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// End the loop if the process finished
|
|
|
|
|
if (ret == WAIT_OBJECT_0)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the return status from the process
|
|
|
|
|
DWORD status = 0;
|
|
|
|
|
GetExitCodeProcess(pi.hProcess, &status);
|
|
|
|
|
|
|
|
|
|
CloseHandle(pipeRead);
|
|
|
|
|
CloseHandle(pipeWrite);
|
|
|
|
|
CloseHandle(pi.hProcess);
|
|
|
|
|
CloseHandle(pi.hThread);
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
#else
|
|
|
|
|
// TODO: Implement suppor for ExecSystemCmd(const string &, string&) on non-Windows platforms
|
|
|
|
|
asIScriptContext *ctx = asGetActiveContext();
|
|
|
|
|
if (ctx)
|
|
|
|
|
ctx->SetException("Oops! This is not yet implemented on non-Windows platforms. Sorry!\n");
|
|
|
|
|
return -1;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function simply calls the system command and returns the status
|
|
|
|
|
// Return of -1 indicates an error. Else the return code is the return status of the executed command
|
|
|
|
|
int ExecSystemCmd(const std::string &str)
|
|
|
|
|
{
|
|
|
|
|
// Check if the command line processor is available
|
|
|
|
|
if (system(0) == 0)
|
|
|
|
|
{
|
|
|
|
|
asIScriptContext *ctx = asGetActiveContext();
|
|
|
|
|
if (ctx)
|
|
|
|
|
ctx->SetException("Command interpreter not available\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
// Convert the command to UTF16 to properly handle unicode path names
|
|
|
|
|
wchar_t bufUTF16[10000];
|
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, bufUTF16, 10000);
|
|
|
|
|
return _wsystem(bufUTF16);
|
|
|
|
|
#else
|
|
|
|
|
return system(str.c_str());
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void registerSystem(asIScriptEngine *engine)
|
|
|
|
|
{
|
2025-05-04 12:48:02 +02:00
|
|
|
engine->SetDefaultNamespace("");
|
2025-05-02 14:17:47 +02:00
|
|
|
engine->RegisterGlobalFunction("int exec(const string &in)", asFUNCTIONPR(ExecSystemCmd, (const std::string &), int), asCALL_CDECL);
|
|
|
|
|
engine->RegisterGlobalFunction("int exec(const string &in, string &out)", asFUNCTIONPR(ExecSystemCmd, (const std::string &, std::string &), int), asCALL_CDECL);
|
|
|
|
|
}
|
|
|
|
|
} // namespace script
|
|
|
|
|
} // namespace satdump
|