aboutsummaryrefslogtreecommitdiff
path: root/src/Exec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Exec.cpp')
-rw-r--r--src/Exec.cpp98
1 files changed, 67 insertions, 31 deletions
diff --git a/src/Exec.cpp b/src/Exec.cpp
index 2eac8bc..6c1a72e 100644
--- a/src/Exec.cpp
+++ b/src/Exec.cpp
@@ -3,24 +3,28 @@
using namespace std;
+const int BUFSIZE = 1024;
+
+// TODO: Redirect stderr to
namespace sibs
{
#if OS_FAMILY == OS_FAMILY_POSIX
Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print)
{
- char buffer[128];
- std::string result;
+ char buffer[BUFSIZE];
+ std::string execStdout;
FILE *pipe = popen(cmd, "r");
if(!pipe)
return Result<ExecResult>::Err("popen() failed");
while(!feof(pipe))
{
- if(fgets(buffer, 128, pipe))
+ int bytesRead = fgets(buffer, BUFSIZE, pipe);
+ if(bytesRead > 0)
{
- result += buffer;
+ execStdout.append(buffer, bytesRead);
if(print)
- printf("%s", buffer);
+ printf("%.*s", bytesRead, buffer);
}
}
@@ -29,7 +33,7 @@ namespace sibs
{
int returned = WEXITSTATUS(processCloseResult);
ExecResult execResult;
- execResult.execStdout = result;
+ execResult.execStdout = move(execStdout);
execResult.exitCode = returned;
return Result<ExecResult>::Ok(execResult);
}
@@ -55,48 +59,80 @@ namespace sibs
}
}
#else
- // TODO(Windows): Redirect stdout (and stderr) to string
+ // Currently stdout is read in text mode so \n is replaced with \r\n, should we read in binary mode instead?
Result<ExecResult> exec(const _tinydir_char_t *cmd, bool print)
{
- char buffer[128];
- std::string result;
+ FileString cmdNonConst = cmd;
+ std::string execStdout;
- STARTUPINFO startupInfo;
- ZeroMemory(&startupInfo, sizeof(startupInfo));
- startupInfo.cb = sizeof(startupInfo);
+ SECURITY_ATTRIBUTES saAttr;
+ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ saAttr.bInheritHandle = TRUE;
+ saAttr.lpSecurityDescriptor = nullptr;
- PROCESS_INFORMATION processInfo;
- ZeroMemory(&processInfo, sizeof(processInfo));
+ HANDLE childReadHandle = nullptr;
+ HANDLE childStdoutHandle = nullptr;
- DWORD exitCode;
-
- if (!CreateProcess(NULL, (LPWSTR)cmd, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo))
+ if (!CreatePipe(&childReadHandle, &childStdoutHandle, &saAttr, 0))
{
string errMsg = "exec unexpected error: ";
errMsg += toUtf8(getLastErrorAsString());
return Result<ExecResult>::Err(errMsg);
}
- WaitForSingleObject(processInfo.hProcess, INFINITE);
- GetExitCodeProcess(processInfo.hProcess, &exitCode);
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
+ if (!SetHandleInformation(childReadHandle, HANDLE_FLAG_INHERIT, 0))
+ goto cleanupAndExit;
+
+ PROCESS_INFORMATION piProcInfo;
+ ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));
+
+ STARTUPINFO siStartInfo;
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
+ siStartInfo.cb = sizeof(STARTUPINFO);
+ siStartInfo.hStdError = nullptr;
+ siStartInfo.hStdOutput = childStdoutHandle;
+ siStartInfo.hStdInput = nullptr;
+ siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ DWORD exitCode;
+
+ if (!CreateProcessW(nullptr, (LPWSTR)cmdNonConst.data(), nullptr, nullptr, TRUE, 0, nullptr, nullptr, &siStartInfo, &piProcInfo))
+ goto cleanupAndExit;
+
+ WaitForSingleObject(piProcInfo.hProcess, INFINITE);
+ GetExitCodeProcess(piProcInfo.hProcess, &exitCode);
+ CloseHandle(piProcInfo.hProcess);
+ CloseHandle(piProcInfo.hThread);
+ CloseHandle(childStdoutHandle);
+ childStdoutHandle = nullptr;
+
+ DWORD bytesRead;
+ CHAR buffer[BUFSIZE];
+ while (true)
+ {
+ BOOL bSuccess = ReadFile(childReadHandle, buffer, BUFSIZE, &bytesRead, nullptr);
+ if (!bSuccess || bytesRead == 0)
+ break;
+
+ execStdout.append(buffer, bytesRead);
+ if (print)
+ printf("%.*s", bytesRead, buffer);
+ }
- if (exitCode == 0)
{
ExecResult execResult;
- execResult.execStdout = result;
+ execResult.execStdout = move(execStdout);
execResult.exitCode = exitCode;
+ CloseHandle(childReadHandle);
return Result<ExecResult>::Ok(execResult);
}
- else
- {
- string errMsg = "Exited with non-zero exit code (";
- errMsg += to_string(exitCode);
- errMsg += "): ";
- errMsg += toUtf8(getLastErrorAsString());
- return Result<ExecResult>::Err(errMsg);
- }
+
+ cleanupAndExit:
+ string errMsg = "exec unexpected error: ";
+ errMsg += toUtf8(getLastErrorAsString());
+ CloseHandle(childReadHandle);
+ CloseHandle(childStdoutHandle);
+ return Result<ExecResult>::Err(errMsg);
}
#endif
}