ultimatepp/bazaar/SysExec/SysExec.cpp
micio dcc5c44115 Removed Exec function, now present in UniStd
git-svn-id: svn://ultimatepp.org/upp/trunk@2500 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2010-06-24 08:16:49 +00:00

311 lines
6.8 KiB
C++

#include "SysExec.h"
#ifdef PLATFORM_POSIX
#include <unistd.h>
#include <sys/wait.h>
#define DEFAULT_PATH "/bin:/usr/bin:."
#if 0
static int execvpe(const char *file, char * const *argv, char * const *envp)
{
char path[PATH_MAX];
const char *searchpath, *esp;
size_t prefixlen, filelen, totallen;
if (strchr(file, '/')) /* Specific path */
return execve(file, argv, envp);
filelen = strlen(file);
searchpath = getenv("PATH");
if (!searchpath)
searchpath = DEFAULT_PATH;
errno = ENOENT; /* Default errno, if execve() doesn't change it */
do
{
esp = strchr(searchpath, ':');
if (esp)
prefixlen = esp - searchpath;
else
prefixlen = strlen(searchpath);
if (prefixlen == 0 || searchpath[prefixlen-1] == '/')
{
totallen = prefixlen + filelen;
if (totallen >= PATH_MAX)
continue;
memcpy(path, searchpath, prefixlen);
memcpy(path + prefixlen, file, filelen);
}
else
{
totallen = prefixlen + filelen + 1;
if (totallen >= PATH_MAX)
continue;
memcpy(path, searchpath, prefixlen);
path[prefixlen] = '/';
memcpy(path + prefixlen + 1, file, filelen);
}
path[totallen] = '\0';
execve(path, argv, envp);
if (errno == E2BIG || errno == ENOEXEC ||
errno == ENOMEM || errno == ETXTBSY)
break; /* Report this as an error, no more search */
searchpath = esp + 1;
}
while (esp);
return -1;
}
#endif
#else
#include <process.h>
#endif
NAMESPACE_UPP
///////////////////////////////////////////////////////////////////////////////////////////////
// parses an args line to be useable by spawnxx functions
static Buffer<char *>_BuildArgs(String const &argline)
{
Array<String> args;
int pos = 0;
char c;
int buflen = 0;
// first arg should be command name... let's make it null
// it MUST be set, as argv[0] has a special meaning
args.Add("");
// skips leading spaces
while ((c = argline[pos]) != 0 && isspace(c))
pos++;
// loop reading args and putting to array
while (c)
{
String &s = args.Add();
buflen++;
while (c && !isspace(c))
{
// reads enquoted strings
if (c == '"')
{
c = argline[++pos];
while (c && c != '"')
{
s << c;
buflen++;
c = argline[++pos];
}
if (c)
c = argline[++pos];
}
else
{
s << c;
buflen++;
c = argline[++pos];
}
}
// skips trailing spaces
while (c && isspace(c))
c = argline[++pos];
}
buflen += (args.GetCount() + 1) * sizeof(char *);
// here we've got an array of args and the total size (in bytes) of them
// we allocates a buffer for arg array
Buffer<char *>buf(buflen);
// we fill the buffer with arg strings
char **bufindex = buf;
char *bufpos = (char *)(buf + args.GetCount() + 1);
int i = 0;
while (i < args.GetCount())
{
String &s = args[i];
strcpy(bufpos, (const char *)s);
*bufindex++ = bufpos;
bufpos += s.GetCount() + 1 ;
i++;
}
*bufindex = 0;
// returns array of args
return buf;
} // END _BuildArgs()
///////////////////////////////////////////////////////////////////////////////////////////////
// parses environment map and builds env array
static Buffer<char *>_BuildEnv(const VectorMap<String, String> &env = Environment())
{
// calculates total environment size
int envSize = 0;
for (int i = 0; i < env.GetCount(); i++)
envSize += env.GetKey(i).GetCount() + env[i].GetCount() + 2 + sizeof(char *);
// we allocates a buffer for env array
Buffer<char *>buf(envSize);
// we fill the buffer with env strings
char **bufindex = buf;
char *bufpos = (char *)(buf + env.GetCount() + 1);
int i = 0;
while (i < env.GetCount())
{
const String &s = env.GetKey(i) + "=" + env[i];
strcpy(bufpos, (const char *)s);
*bufindex++ = bufpos;
bufpos += s.GetCount() + 1 ;
i++;
}
*bufindex = 0;
// returns array of args
return buf;
} // END _BuildEnv()
///////////////////////////////////////////////////////////////////////////////////////////////
// executes an external command, passing a command line to it and gathering the output
// from both stdout and stderr
bool SysExec(String const &command, String const &args, const VectorMap<String, String> &Environ, String &OutStr, String &ErrStr)
{
FILE *fp;
// flushes both stdout and stderr files
fflush(stdout);
fflush(stderr);
// saves stdout stream state
int saveStdout = dup(fileno(stdout));
// creates and opens a temporary file and assigns stdout to it
int OutFile = fileno(tmpfile());
dup2(OutFile, 1);
// saves stderr stream state
int saveStderr = dup(fileno(stderr));
// creates and opens a temporary file and assigns stdout to it
int ErrFile = fileno(tmpfile());
dup2(ErrFile, 2);
// builds the arguments and the environment
Buffer<char *>argv = _BuildArgs(args);
Buffer<char *>envv = _BuildEnv(Environ);
// executes the command
int result = 0;
#ifdef PLATFORM_POSIX
pid_t pID = fork();
if (pID == 0)
{
// Code only executed by child process
// exec svn, function shall not return if all ok
result = execvpe(command, argv, envv);
// terminates child process
_exit(result);
}
else if (pID < 0)
{
// code executed only if couldn't fork
Cerr() << "Couldn't fork...\n";
result = -1;
}
else
{
// Code only executed by parent process
// waits for parent to terminate
wait(&result);
}
#else
result = _spawnvpe(_P_WAIT, command, argv, envv);
#endif
// flushes both stdout and stderr files
fflush(stdout);
fflush(stderr);
// restores stdout and stderr handles
dup2(saveStdout, 1);
dup2(saveStderr, 2);
if (result == -1)
Cerr() << "Error spawning process\n";
// allocates char buffers and reads out end err data into them
OutStr.Clear();
int OutSize = lseek(OutFile, 0L, SEEK_END);
if (OutSize > 0)
{
char *buf = (char *)malloc(OutSize + 1);
lseek(OutFile, 0L, SEEK_SET);
read(OutFile, buf, OutSize);
buf[OutSize] = 0;
OutStr.Cat(buf);
free(buf);
}
ErrStr.Clear();
int ErrSize = lseek(ErrFile, 0L, SEEK_END);
if (ErrSize > 0)
{
char *buf = (char *)malloc(ErrSize + 1);
lseek(ErrFile, 0L, SEEK_SET);
read(ErrFile, buf, ErrSize);
buf[ErrSize] = 0;
ErrStr.Cat(buf);
free(buf);
}
// closes files
close(OutFile);
close(ErrFile);
return (!result);
} // END SysExec()
bool SysExec(String const &command, String const &args, String &OutStr, String &ErrStr)
{
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args, const VectorMap<String, String> &Environ, String &OutStr)
{
String ErrStr;
return SysExec(command, args, Environ, OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args, String &OutStr)
{
String ErrStr;
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
bool SysExec(String const &command, String const &args)
{
String OutStr, ErrStr;
return SysExec(command, args, Environment(), OutStr, ErrStr);
} // END SysExec()
END_UPP_NAMESPACE