\r
// Author: Andy Rushton\r
// Copyright: (c) Southampton University 1999-2004\r
-// (c) Andy Rushton 2004-2009\r
+// (c) Andy Rushton 2004 onwards\r
// License: BSD License, see ../docs/license.html\r
\r
////////////////////////////////////////////////////////////////////////////////\r
#include <stdlib.h>\r
\r
#ifdef MSWINDOWS\r
+#ifdef __BORLANDC__\r
+// missing declaration in Borland headers\r
+LPTCH WINAPI GetEnvironmentStringsA(void);\r
+#endif\r
#else\r
+extern char** environ;\r
#include <signal.h>\r
#include <errno.h>\r
#include <sys/wait.h>\r
// set of characters requiring escapes\r
#ifdef MSWINDOWS\r
#else\r
- case '\\': case '\'': case '\"': case '`': case '(': case ')': \r
+ case '\\': case '\'': case '\"': case '`': case '(': case ')':\r
case '&': case '|': case '<': case '>': case '*': case '?': case '!':\r
result += '\\';\r
result += arg[i];\r
#else\r
// Unix utilities\r
\r
- extern char** environ;\r
-\r
static unsigned envp_size(char* const* envp)\r
{\r
unsigned size = 0;\r
return result;\r
}\r
\r
+ bool env_vector::present (const std::string& name) const\r
+ {\r
+ unsigned i = 0;\r
+ while(m_env[i])\r
+ {\r
+ std::string current_name;\r
+ std::string current_value;\r
+ envp_extract(current_name, current_value, m_env, i);\r
+ if (envp_equal(name,current_name))\r
+ return true;\r
+ }\r
+ return false;\r
+ }\r
+\r
std::string env_vector::operator [] (const std::string& name) const\r
{\r
return get(name);\r
\r
#endif\r
\r
+ void subprocess::set_error(int e)\r
+ {\r
+ m_err = e;\r
+ }\r
+\r
void subprocess::add_variable(const std::string& name, const std::string& value)\r
{\r
m_env.add(name, value);\r
return m_env.remove(name);\r
}\r
\r
+ const env_vector& subprocess::get_variables(void) const\r
+ {\r
+ return m_env;\r
+ }\r
+\r
#ifdef MSWINDOWS\r
\r
bool subprocess::spawn(const std::string& path, const arg_vector& argv,\r
if (connect_stderr) CloseHandle(parent_stderr);\r
if (!created)\r
{\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
close_stdin();\r
close_stdout();\r
close_stderr();\r
DWORD exit_status = 0;\r
if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))\r
{\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
result = false;\r
}\r
else if (exit_status != 0)\r
\r
int stdin_pipe [2] = {-1, -1};\r
if (connect_stdin)\r
- pipe(stdin_pipe);\r
+ if (::pipe(stdin_pipe) != 0)\r
+ set_error(errno);\r
\r
int stdout_pipe [2] = {-1, -1};\r
if (connect_stdout)\r
- pipe(stdout_pipe);\r
+ if (::pipe(stdout_pipe) != 0)\r
+ set_error(errno);\r
\r
int stderr_pipe [2] = {-1, -1};\r
if (connect_stderr)\r
- pipe(stderr_pipe);\r
+ if (::pipe(stderr_pipe) != 0)\r
+ set_error(errno);\r
\r
// now create the subprocess\r
// In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec\r
switch(m_pid)\r
{\r
case -1: // failed to fork\r
- m_err = errno;\r
+ set_error(errno);\r
if (connect_stdin)\r
{\r
::close(stdin_pipe[0]);\r
if (connect_stdin)\r
{\r
::close(stdin_pipe[1]);\r
- dup2(stdin_pipe[0],STDIN_FILENO);\r
+ ::dup2(stdin_pipe[0],STDIN_FILENO);\r
}\r
if (connect_stdout)\r
{\r
::close(stdout_pipe[0]);\r
- dup2(stdout_pipe[1],STDOUT_FILENO);\r
+ ::dup2(stdout_pipe[1],STDOUT_FILENO);\r
}\r
if (connect_stderr)\r
{\r
::close(stderr_pipe[0]);\r
- dup2(stderr_pipe[1],STDERR_FILENO);\r
+ ::dup2(stderr_pipe[1],STDERR_FILENO);\r
}\r
execve(path.c_str(), argv.argv(), m_env.envp());\r
// will only ever get here if the exec() failed completely - *must* now exit the child process\r
close_stderr();\r
if (!TerminateJobObject(m_job, (UINT)-1))\r
{\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
return false;\r
}\r
return true;\r
close_stderr();\r
if (::kill(m_pid, SIGINT) == -1)\r
{\r
- m_err = errno;\r
+ set_error(errno);\r
return false;\r
}\r
return true;\r
DWORD bytes = 0;\r
if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))\r
{\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
close_stdin();\r
return -1;\r
}\r
int bytes = write(m_child_in, buffer.c_str(), buffer.size());\r
if (bytes == -1)\r
{\r
- m_err = errno;\r
+ set_error(errno);\r
close_stdin();\r
return -1;\r
}\r
if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))\r
{\r
if (GetLastError() != ERROR_BROKEN_PIPE)\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
close_stdout();\r
delete[] tmp;\r
return -1;\r
int bytes = read(m_child_out, tmp, buffer_size);\r
if (bytes == -1)\r
{\r
- m_err = errno;\r
+ set_error(errno);\r
close_stdout();\r
delete[] tmp;\r
return -1;\r
if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))\r
{\r
if (GetLastError() != ERROR_BROKEN_PIPE)\r
- m_err = GetLastError();\r
+ set_error(GetLastError());\r
close_stderr();\r
delete[] tmp;\r
return -1;\r
int bytes = read(m_child_err, tmp, buffer_size);\r
if (bytes == -1)\r
{\r
- m_err = errno;\r
+ set_error(errno);\r
close_stderr();\r
delete[] tmp;\r
return -1;\r
\r
std::string subprocess::error_text(void) const\r
{\r
- if (m_err == 0) return std::string();\r
+ if (!error()) return std::string();\r
char* message;\r
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
0,\r
\r
std::string subprocess::error_text(void) const\r
{\r
- if (m_err == 0) return std::string();\r
+ if (!error()) return std::string();\r
char* text = strerror(m_err);\r
if (text) return std::string(text);\r
return "error number " + dformat("%d",m_err);\r
std::vector<std::string> result;\r
// convert the raw text into a vector of strings, each corresponding to a line\r
// in the process, strip out platform-specific line-endings\r
+ result.push_back(std::string());\r
for (unsigned i = 0; i < m_text.size(); i++)\r
{\r
// handle any kind of line-ending - Dos, Unix or MacOS\r
return m_env.remove(name);\r
}\r
\r
+ const env_vector& async_subprocess::get_variables(void) const\r
+ {\r
+ return m_env;\r
+ }\r
+\r
#ifdef MSWINDOWS\r
\r
bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,\r
\r
int stdin_pipe [2] = {-1, -1};\r
if (connect_stdin)\r
- pipe(stdin_pipe);\r
+ if (::pipe(stdin_pipe) != 0)\r
+ set_error(errno);\r
\r
int stdout_pipe [2] = {-1, -1};\r
if (connect_stdout)\r
- pipe(stdout_pipe);\r
+ if (::pipe(stdout_pipe) != 0)\r
+ set_error(errno);\r
\r
int stderr_pipe [2] = {-1, -1};\r
if (connect_stderr)\r
- pipe(stderr_pipe);\r
+ if (::pipe(stderr_pipe) != 0)\r
+ set_error(errno);\r
\r
// now create the subprocess\r
// In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec\r
if (connect_stdin)\r
{\r
::close(stdin_pipe[1]);\r
- dup2(stdin_pipe[0],STDIN_FILENO);\r
+ ::dup2(stdin_pipe[0],STDIN_FILENO);\r
}\r
if (connect_stdout)\r
{\r
::close(stdout_pipe[0]);\r
- dup2(stdout_pipe[1],STDOUT_FILENO);\r
+ ::dup2(stdout_pipe[1],STDOUT_FILENO);\r
}\r
if (connect_stderr)\r
{\r
::close(stderr_pipe[0]);\r
- dup2(stderr_pipe[1],STDERR_FILENO);\r
+ ::dup2(stderr_pipe[1],STDERR_FILENO);\r
}\r
- execve(path.c_str(), argv.argv(), m_env.envp());\r
+ ::execve(path.c_str(), argv.argv(), m_env.envp());\r
// will only ever get here if the exec() failed completely - *must* now exit the child process\r
// by using errno, the parent has some chance of diagnosing the cause of the problem\r
- exit(errno);\r
+ ::exit(errno);\r
}\r
break;\r
default: // in parent\r
\r
std::string async_subprocess::error_text(void) const\r
{\r
- if (m_err == 0) return std::string();\r
+ if (!error()) return std::string();\r
char* message;\r
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
0,\r
\r
std::string async_subprocess::error_text(void) const\r
{\r
- if (m_err == 0) return std::string();\r
+ if (!error()) return std::string();\r
char* text = strerror(m_err);\r
if (text) return std::string(text);\r
return "error number " + dformat("%d",m_err);\r