[GRASS-SVN] r40149 - grass/trunk/lib/gis
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Dec 26 23:51:18 EST 2009
Author: glynn
Date: 2009-12-26 23:51:17 -0500 (Sat, 26 Dec 2009)
New Revision: 40149
Modified:
grass/trunk/lib/gis/spawn.c
Log:
Don't use "switch" for testing for SF_* constants
casting to "int" isn't robust, and other alternatives have portability issues
Add Windows version using CreateProcess(), supports redirection
Modified: grass/trunk/lib/gis/spawn.c
===================================================================
--- grass/trunk/lib/gis/spawn.c 2009-12-27 04:48:01 UTC (rev 40148)
+++ grass/trunk/lib/gis/spawn.c 2009-12-27 04:51:17 UTC (rev 40149)
@@ -24,9 +24,17 @@
#include <errno.h>
#include <sys/types.h>
+#define USE_CREATE_PROCESS 1
+
#ifndef __MINGW32__
#include <sys/wait.h>
+#else
+#ifdef USE_CREATE_PROCESS
+#include <windows.h>
+#else
+typedef void *HANDLE;
#endif
+#endif
#include <grass/config.h>
#include <grass/gis.h>
#include <grass/glocale.h>
@@ -211,13 +219,325 @@
#ifdef __MINGW32__
-static void do_redirects(const struct redirect *redirects, int num_redirects)
+#ifdef USE_CREATE_PROCESS
+
+struct buffer {
+ char *str;
+ size_t len;
+ size_t size;
+};
+
+static const int INCREMENT = 50;
+
+static void clear(struct buffer *b)
{
+ b->len = 0;
+ b->str[b->len] = '\0';
+}
+
+static void init(struct buffer *b)
+{
+ b->str = G_malloc(1);
+ b->size = 1;
+ clear(b);
+}
+
+static char *release(struct buffer *b)
+{
+ char *p = b->str;
+
+ b->str = NULL;
+ b->size = 0;
+ b->len = 0;
+
+ return p;
+}
+
+static void finish(struct buffer *b)
+{
+ if (b->str)
+ G_free(b->str);
+ release(b);
+}
+
+static void ensure(struct buffer *b, size_t n)
+{
+ if (b->size <= b->len + n + 1) {
+ b->size = b->len + n + INCREMENT;
+ b->str = G_realloc(b->str, b->size);
+ }
+}
+
+static void append(struct buffer *b, const char *str)
+{
+ size_t n = strlen(str);
+
+ ensure(b, n);
+ memcpy(&b->str[b->len], str, n);
+ b->len += n;
+ b->str[b->len] = '\0';
+}
+
+static void append_char(struct buffer *b, char c)
+{
+ ensure(b, 1);
+ b->str[b->len] = c;
+ b->len++;
+ b->str[b->len] = '\0';
+}
+
+static char *make_command_line(const char **argv)
+{
+ struct buffer result;
+ struct buffer buf;
+ int i;
+
+ init(&result);
+ init(&buf);
+
+ for (i = 0; argv[i]; i++) {
+ const char *arg = argv[i];
+ int quote;
+ int j;
+
+ clear(&buf);
+
+ if (result.len > 0)
+ append_char(&result, ' ');
+
+ quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
+
+ if (quote)
+ append_char(&result, '\"');
+
+ for (j = 0; arg[j]; j++) {
+ int c = arg[j];
+ int k;
+
+ switch (c) {
+ case '\\':
+ append_char(&buf, '\\');
+ break;
+ case '\"':
+ for (k = 0; k < buf.len; k++)
+ append(&result, "\\\\");
+ clear(&buf);
+ append(&result, "\\\"");
+ break;
+ default:
+ if (buf.len > 0) {
+ append(&result, buf.str);
+ clear(&buf);
+ }
+ append_char(&result, c);
+ }
+ }
+
+ if (buf.len > 0)
+ append(&result, buf.str);
+
+ if (quote) {
+ append(&result, buf.str);
+ append_char(&result, '\"');
+ }
+ }
+
+ finish(&buf);
+ return release(&result);
+}
+
+static char *make_environment(const char **envp)
+{
+ struct buffer result;
+ int i;
+
+ init(&result);
+
+ for (i = 0; envp[i]; i++) {
+ const char *env = envp[i];
+
+ append(&result, env);
+ append_char(&result, '\0');
+ }
+
+ return release(&result);
+}
+
+static char *check_program(const char *pgm, const char *dir, const char *ext)
+{
+ char pathname[GPATH_MAX];
+
+ sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
+ return access(pathname, 0) == 0
+ ? G_store(pathname)
+ : NULL;
+}
+
+static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
+{
+ char *result;
+ int i;
+
+ if (result = check_program(pgm, dir, ""), result)
+ return result;
+
+ for (i = 0; pathext[i]; i++) {
+ const char *ext = pathext[i];
+ if (result = check_program(pgm, dir, ext), result)
+ return result;
+ }
+
+ return NULL;
+}
+
+static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
+{
+ char *result = NULL;
+ int i;
+
+ if (strchr(pgm, '\\') || strchr(pgm, '/')) {
+ if (result = find_program_ext(pgm, "", pathext), result)
+ return result;
+ }
+ else {
+ if (result = find_program_ext(pgm, ".", pathext), result)
+ return result;
+
+ for (i = 0; path[i]; i++) {
+ const char *dir = path[i];
+ if (result = find_program_ext(pgm, dir, pathext), result)
+ return result;
+ }
+ }
+
+ return NULL;
+}
+
+static char *find_program(const char *pgm)
+{
+ char **path = G_tokenize(getenv("PATH"), ";");
+ char **pathext = G_tokenize(getenv("PATHEXT"), ";");
+ char *result = find_program_dir_ext(pgm, path, pathext);
+ G_free_tokens(path);
+ G_free_tokens(pathext);
+ return result;
+}
+
+static HANDLE get_handle(int fd)
+{
+ HANDLE h1, h2;
+
+ if (fd < 0)
+ return INVALID_HANDLE_VALUE;
+
+ h1 = (HANDLE) _get_osfhandle(fd);
+ if (!DuplicateHandle(GetCurrentProcess(), h1,
+ GetCurrentProcess(), &h2,
+ DUPLICATE_SAME_ACCESS, 1, 0))
+ return INVALID_HANDLE_VALUE;
+
+ return h2;
+}
+
+static int win_spawn(const char *cmd, const char **argv, const char **envp,
+ const char *cwd, HANDLE handles[3], int background)
+{
+ char *args = make_command_line(argv);
+ char *env = make_environment(envp);
+ char *program = find_program(cmd);
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ BOOL result;
+ DWORD exitcode;
+
+ if (!program) {
+ G_free(args);
+ G_free(env);
+ return -1;
+ }
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ si.dwFlags |= STARTF_USESTDHANDLES;
+ si.hStdInput = handles[0];
+ si.hStdOutput = handles[1];
+ si.hStdError = handles[2];
+
+ result = CreateProcess(
+ program, /* lpApplicationName */
+ args, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ 1, /* bInheritHandles */
+ 0, /* dwCreationFlags */
+ env, /* lpEnvironment */
+ cwd, /* lpCurrentDirectory */
+ &si, /* lpStartupInfo */
+ &pi /* lpProcessInformation */
+ );
+
+ G_free(args);
+ G_free(env);
+ G_free(program);
+
+ if (!background) {
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ if (!GetExitCodeProcess(pi.hProcess, &exitcode))
+ return -1;
+ return (int) exitcode;
+ }
+
+ return pi.dwProcessId;
+}
+
+static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ handles[i] = get_handle(i);
+
+ for (i = 0; i < num_redirects; i++) {
+ struct redirect *r = &redirects[i];
+
+ if (r->dst_fd < 0 || r->dst_fd > 2) {
+ G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
+ continue;
+ }
+
+ if (r->file) {
+ r->src_fd = open(r->file, r->mode, 0666);
+
+ if (r->src_fd < 0) {
+ G_warning(_("G_spawn: unable to open file %s"), r->file);
+ _exit(127);
+ }
+
+ handles[r->dst_fd] = get_handle(r->src_fd);
+
+ close(r->src_fd);
+
+ }
+ else if (r->src_fd >= 0) {
+ handles[r->dst_fd] = get_handle(r->src_fd);
+ }
+ else
+ handles[r->dst_fd] = INVALID_HANDLE_VALUE;
+ }
+}
+
+#else
+
+static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
+{
if (num_redirects > 0)
G_fatal_error
("G_spawn_ex: redirection not (yet) supported on Windows");
}
+#endif
+
static void add_binding(const char **env, int *pnum, const struct binding *b)
{
char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
@@ -256,16 +576,20 @@
return newenv;
}
-static int do_spawn(const struct spawn *sp, const char *command)
+static int do_spawn(struct spawn *sp, const char *command)
{
+ HANDLE handles[3];
const char **env;
int status;
- do_redirects(sp->redirects, sp->num_redirects);
+ do_redirects(sp->redirects, sp->num_redirects, handles);
env = do_bindings(sp->bindings, sp->num_bindings);
- status =
- spawnvpe(sp->background ? _P_NOWAIT : _P_WAIT, command, sp->args, env);
+#ifdef USE_CREATE_PROCESS
+ status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background);
+#else
+ status = spawnvpe(sp->background ? _P_NOWAIT : _P_WAIT, command, sp->args, env);
+#endif
if (!sp->background && status < 0)
G_warning(_("Unable to execute command"));
@@ -499,11 +823,11 @@
const char *arg = NEXT_ARG(va, const char *);
const char *var, *val;
- switch ((int)arg) {
- case 0:
+ if (!arg) {
sp->args[sp->num_args++] = NULL;
break;
- case ((int)SF_REDIRECT_FILE):
+ }
+ else if (arg == SF_REDIRECT_FILE) {
sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
sp->redirects[sp->num_redirects].src_fd = -1;
@@ -511,59 +835,53 @@
sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
sp->num_redirects++;
- break;
- case ((int)SF_REDIRECT_DESCRIPTOR):
+ }
+ else if (arg == SF_REDIRECT_DESCRIPTOR) {
sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
sp->redirects[sp->num_redirects].file = NULL;
sp->num_redirects++;
- break;
- case ((int)SF_CLOSE_DESCRIPTOR):
+ }
+ else if (arg == SF_CLOSE_DESCRIPTOR) {
sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
sp->redirects[sp->num_redirects].src_fd = -1;
sp->redirects[sp->num_redirects].file = NULL;
sp->num_redirects++;
- break;
- case ((int)SF_SIGNAL):
+ }
+ else if (arg == SF_SIGNAL) {
sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
sp->signals[sp->num_signals].valid = 0;
sp->num_signals++;
- break;
- case ((int)SF_VARIABLE):
+ }
+ else if (arg == SF_VARIABLE) {
var = NEXT_ARG(va, const char *);
val = getenv(var);
sp->args[sp->num_args++] = val ? val : "";
- break;
- case ((int)SF_BINDING):
+ }
+ else if (arg == SF_BINDING) {
sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
sp->num_bindings++;
- break;
- case ((int)SF_BACKGROUND):
+ }
+ else if (arg == SF_BACKGROUND) {
sp->background = 1;
- break;
- case ((int)SF_DIRECTORY):
+ }
+ else if (arg == SF_DIRECTORY) {
sp->directory = NEXT_ARG(va, const char *);
- break;
- case ((int)SF_ARGVEC):
+ }
+ else if (arg == SF_ARGVEC) {
parse_argvec(sp, NEXT_ARG(va, const char **));
-
- break;
- default:
+ }
+ else
sp->args[sp->num_args++] = arg;
- break;
- }
-
- if (!arg)
- break;
}
}
@@ -573,11 +891,11 @@
const char *arg = va_arg(va, const char *);
const char *var, *val;
- switch ((int)arg) {
- case 0:
+ if (!arg) {
sp->args[sp->num_args++] = NULL;
break;
- case ((int)SF_REDIRECT_FILE):
+ }
+ else if (arg == SF_REDIRECT_FILE) {
sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
sp->redirects[sp->num_redirects].src_fd = -1;
@@ -585,59 +903,52 @@
sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
sp->num_redirects++;
- break;
- case ((int)SF_REDIRECT_DESCRIPTOR):
+ }
+ else if (arg == SF_REDIRECT_DESCRIPTOR) {
sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
sp->redirects[sp->num_redirects].file = NULL;
sp->num_redirects++;
- break;
- case ((int)SF_CLOSE_DESCRIPTOR):
+ }
+ else if (arg == SF_CLOSE_DESCRIPTOR) {
sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
sp->redirects[sp->num_redirects].src_fd = -1;
sp->redirects[sp->num_redirects].file = NULL;
sp->num_redirects++;
- break;
- case ((int)SF_SIGNAL):
+ }
+ else if (arg == SF_SIGNAL) {
sp->signals[sp->num_signals].which = va_arg(va, int);
sp->signals[sp->num_signals].action = va_arg(va, int);
sp->signals[sp->num_signals].signum = va_arg(va, int);
sp->signals[sp->num_signals].valid = 0;
sp->num_signals++;
- break;
- case ((int)SF_VARIABLE):
+ }
+ else if (arg == SF_VARIABLE) {
var = va_arg(va, char *);
val = getenv(var);
sp->args[sp->num_args++] = val ? val : "";
- break;
- case ((int)SF_BINDING):
+ }
+ else if (arg == SF_BINDING) {
sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
sp->num_bindings++;
- break;
- case ((int)SF_BACKGROUND):
+ }
+ else if (arg == SF_BACKGROUND) {
sp->background = 1;
- break;
- case ((int)SF_DIRECTORY):
+ }
+ else if (arg == SF_DIRECTORY) {
sp->directory = va_arg(va, const char *);
-
- break;
- case ((int)SF_ARGVEC):
+ }
+ else if (arg == SF_ARGVEC) {
parse_argvec(sp, va_arg(va, const char **));
-
- break;
- default:
+ }
+ else
sp->args[sp->num_args++] = arg;
- break;
- }
-
- if (!arg)
- break;
}
}
@@ -685,3 +996,4 @@
return do_spawn(&sp, command);
}
+
More information about the grass-commit
mailing list