[GRASS-SVN] r40547 - grass/branches/develbranch_6/lib/gis

svn_grass at osgeo.org svn_grass at osgeo.org
Tue Jan 19 02:34:45 EST 2010


Author: glynn
Date: 2010-01-19 02:34:44 -0500 (Tue, 19 Jan 2010)
New Revision: 40547

Modified:
   grass/branches/develbranch_6/lib/gis/spawn.c
Log:
Sync spawn.c to 7.0


Modified: grass/branches/develbranch_6/lib/gis/spawn.c
===================================================================
--- grass/branches/develbranch_6/lib/gis/spawn.c	2010-01-19 07:32:53 UTC (rev 40546)
+++ grass/branches/develbranch_6/lib/gis/spawn.c	2010-01-19 07:34:44 UTC (rev 40547)
@@ -26,6 +26,8 @@
 
 #ifndef __MINGW32__
 #include <sys/wait.h>
+#else
+#include <windows.h>
 #endif
 #include <grass/config.h>
 #include <grass/gis.h>
@@ -56,187 +58,428 @@
  * \return process status on success
  */
 
-#ifdef __MINGW32__
+struct redirect
+{
+    int dst_fd;
+    int src_fd;
+    const char *file;
+    int mode;
+};
 
-int G_spawn(const char *command, ...)
+struct signal
 {
-    va_list va;
+    int which;
+    int action;
+    int signum;
+    int valid;
+#ifndef __MINGW32__
+    struct sigaction old_act;
+    sigset_t old_mask;
+#endif
+};
+
+struct binding
+{
+    const char *var;
+    const char *val;
+};
+
+struct spawn
+{
     const char *args[MAX_ARGS];
-    int num_args = 0;
+    int num_args;
+    struct redirect redirects[MAX_REDIRECTS];
+    int num_redirects;
+    struct signal signals[MAX_SIGNALS];
+    int num_signals;
+    struct binding bindings[MAX_BINDINGS];
+    int num_bindings;
+    int background;
+    const char *directory;
+};
 
-    va_start(va, command);
+static void parse_arglist(struct spawn *sp, va_list va);
+static void parse_argvec(struct spawn *sp, const char **va);
 
-    for (num_args = 0; num_args < MAX_ARGS;) {
-	const char *arg = va_arg(va, const char *);
+#ifdef __MINGW32__
 
-	args[num_args++] = arg;
-	if (!arg)
-	    break;
-    }
+struct buffer {
+    char *str;
+    size_t len;
+    size_t size;
+};
 
-    va_end(va);
+static const int INCREMENT = 50;
 
-    if (num_args >= MAX_ARGS) {
-	G_warning(_("Too many arguments"));
-	return -1;
+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);
     }
+}
 
-    G_debug(3, "spawning '%s' ...", command);
+static void append(struct buffer *b, const char *str)
+{
+    size_t n = strlen(str);
 
-    return _spawnvp(_P_WAIT, command, args);
+    ensure(b, n);
+    memcpy(&b->str[b->len], str, n);
+    b->len += n;
+    b->str[b->len] = '\0';
 }
 
-#else
+static void append_char(struct buffer *b, char c)
+{
+    ensure(b, 1);
+    b->str[b->len] = c;
+    b->len++;
+    b->str[b->len] = '\0';
+}
 
-int G_spawn(const char *command, ...)
+static void escape_arg(struct buffer *result, const char *arg)
 {
-    va_list va;
-    char *args[MAX_ARGS];
-    int num_args = 0;
-    struct sigaction act, intr, quit;
-    sigset_t block, oldmask;
-    int status = -1;
-    pid_t pid;
+    struct buffer buf;
+    int quote, j;
 
-    va_start(va, command);
+    init(&buf);
 
-    for (num_args = 0; num_args < MAX_ARGS;) {
-	char *arg = va_arg(va, char *);
+    quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
 
-	args[num_args++] = arg;
-	if (!arg)
+    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);
+	}
     }
 
-    va_end(va);
+    if (buf.len > 0)
+	append(result, buf.str);
 
-    if (num_args >= MAX_ARGS) {
-	G_warning(_("Too many arguments"));
-	return -1;
+    if (quote) {
+	append(result, buf.str);
+	append_char(result, '\"');
     }
 
-    sigemptyset(&act.sa_mask);
-    act.sa_flags = SA_RESTART;
+    finish(&buf);
+}
 
-    act.sa_handler = SIG_IGN;
-    if (sigaction(SIGINT, &act, &intr) < 0)
-	goto error_1;
-    if (sigaction(SIGQUIT, &act, &quit) < 0)
-	goto error_2;
+static char *check_program(const char *pgm, const char *dir, const char *ext)
+{
+    char pathname[GPATH_MAX];
 
-    sigemptyset(&block);
-    sigaddset(&block, SIGCHLD);
-    if (sigprocmask(SIG_BLOCK, &block, &oldmask) < 0)
-	goto error_3;
+    sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
+    return access(pathname, 0) == 0
+	? G_store(pathname)
+	: NULL;
+}
 
-    G_debug(3, "forking '%s' ...", command);
+static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
+{
+    char *result;
+    int i;
 
-    pid = fork();
+    if (result = check_program(pgm, dir, ""), result)
+	return result;
 
-    if (pid < 0) {
-	G_warning(_("Unable to create a new process"));
-	goto error_4;
+    for (i = 0; pathext[i]; i++) {
+	const char *ext = pathext[i];
+	if (result = check_program(pgm, dir, ext), result)
+	    return result;
     }
 
-    if (pid == 0) {
-	sigaction(SIGINT, &intr, NULL);
-	sigaction(SIGQUIT, &quit, NULL);
+    return NULL;
+}
 
-	execvp(command, args);
-	G_warning(_("Unable to execute command"));
-	_exit(127);
+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 {
-	pid_t n;
+	if (result = find_program_ext(pgm, ".", pathext), result)
+	    return result;
 
-	do
-	    n = waitpid(pid, &status, 0);
-	while (n == (pid_t) - 1 && errno == EINTR);
+	for (i = 0; path[i]; i++) {
+	    const char *dir = path[i];
+	    if (result = find_program_ext(pgm, dir, pathext), result)
+		return result;
+	}
+    }
 
-	if (n != pid)
-	    status = -1;
+    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 char *make_command_line(int shell, const char *cmd, const char **argv)
+{
+    struct buffer result;
+    int i;
+
+    init(&result);
+
+    if (shell) {
+	const char *comspec = getenv("COMSPEC");
+	append(&result, comspec ? comspec : "cmd.exe");
+	append(&result, " /c ");
+	escape_arg(&result, cmd);
     }
 
-  error_4:
-    sigprocmask(SIG_SETMASK, &oldmask, NULL);
-  error_3:
-    sigaction(SIGQUIT, &quit, NULL);
-  error_2:
-    sigaction(SIGINT, &intr, NULL);
-  error_1:
-    return status;
+    for (i = shell ? 1 : 0; argv[i]; i++) {
+	if (result.len > 0)
+	    append_char(&result, ' ');
+	escape_arg(&result, argv[i]);
+    }
+
+    return release(&result);
 }
 
-#endif /*__MINGW32__*/
+static char *make_environment(const char **envp)
+{
+    struct buffer result;
+    int i;
 
-struct redirect
+    init(&result);
+
+    for (i = 0; envp[i]; i++) {
+	const char *env = envp[i];
+
+	append(&result, env);
+	append_char(&result, '\0');
+    }
+
+    return release(&result);
+}
+
+static HANDLE get_handle(int fd)
 {
-    int dst_fd;
-    int src_fd;
-    const char *file;
-    int mode;
-};
+    HANDLE h1, h2;
 
-struct signal
+    if (fd < 0)
+	return INVALID_HANDLE_VALUE;
+
+    h1 = (HANDLE) _get_osfhandle(fd);
+    if (!DuplicateHandle(GetCurrentProcess(), h1,
+			 GetCurrentProcess(), &h2,
+			 0, TRUE, DUPLICATE_SAME_ACCESS))
+	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,
+		     int shell)
 {
-    int which;
-    int action;
-    int signum;
-    int valid;
-#ifndef __MINGW32__
-    struct sigaction old_act;
-    sigset_t old_mask;
-#endif
-};
+    char *args = make_command_line(shell, cmd, argv);
+    char *env = make_environment(envp);
+    char *program = shell ? NULL : find_program(cmd);
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+    BOOL result;
+    DWORD exitcode;
 
-struct binding
+    if (!shell) {
+	G_debug(3, "win_spawn: program = %s", program);
+
+	if (!program) {
+	    G_free(args);
+	    G_free(env);
+	    return -1;
+	}
+    }
+
+    G_debug(3, "win_spawn: args = %s", args);
+
+    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 (!result) {
+	G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
+	return -1;
+    }
+
+    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])
 {
-    const char *var;
-    const char *val;
-};
+    int i;
 
-static const char *args[MAX_ARGS];
-static int num_args;
-static struct redirect redirects[MAX_REDIRECTS];
-static int num_redirects;
-static struct signal signals[MAX_SIGNALS];
-static int num_signals;
-static struct binding bindings[MAX_BINDINGS];
-static int num_bindings;
-static int background;
-static const char *directory;
+    for (i = 0; i < 3; i++)
+	handles[i] = get_handle(i);
 
-#ifdef __MINGW32__
+    for (i = 0; i < num_redirects; i++) {
+	struct redirect *r = &redirects[i];
 
-static void do_redirects(struct redirect *redirects, int num_redirects)
+	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;
+    }
+}
+
+static void add_binding(const char **env, int *pnum, const struct binding *b)
 {
-    if (num_redirects > 0)
-	G_fatal_error
-	    ("G_spawn_ex: redirection not (yet) supported on Windows");
+    char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
+    int n = *pnum;
+    int i;
+
+    sprintf(str, "%s=%s", b->var, b->val);
+
+    for (i = 0; i < n; i++)
+	if (G_strcasecmp(env[i], b->var) == 0) {
+	    env[i] = str;
+	    return;
+	}
+
+    env[n++] = str;
+    *pnum = n;
 }
 
-static char **do_bindings(char **env, struct binding *bindings,
-			  int num_bindings)
+static const char **do_bindings(const struct binding *bindings, int num_bindings)
 {
-    if (num_bindings > 0)
-	G_fatal_error
-	    ("G_spawn_ex: redirection not (yet) supported on Windows");
+    const char **newenv;
+    int i, n;
 
-    return env;
+    for (i = 0; _environ[i]; i++)
+	;
+    n = i;
+
+    newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
+
+    for (i = 0; i < n; i++)
+	newenv[i] = _environ[i];
+
+    for (i = 0; i < num_bindings; i++)
+	add_binding(newenv, &n, &bindings[i]);
+
+    return newenv;
 }
 
-static int do_spawn(const char *command)
+static int do_spawn(struct spawn *sp, const char *command)
 {
-    char **env;
+    HANDLE handles[3];
+    const char **env;
     int status;
 
-    do_redirects(redirects, num_redirects);
-    env = do_bindings(_environ, bindings, num_bindings);
+    do_redirects(sp->redirects, sp->num_redirects, handles);
+    env = do_bindings(sp->bindings, sp->num_bindings);
 
-    status =
-	spawnvpe(background ? _P_NOWAIT : _P_WAIT, command, args, env);
+    status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
 
-    if (!background && status < 0)
+    if (!sp->background && status < 0)
 	G_warning(_("Unable to execute command"));
 
     return status;
@@ -244,13 +487,13 @@
 
 #else /* __MINGW32__ */
 
-static int undo_signals(struct signal *signals, int num_signals, int which)
+static int undo_signals(const struct signal *signals, int num_signals, int which)
 {
     int error = 0;
     int i;
 
     for (i = num_signals - 1; i >= 0; i--) {
-	struct signal *s = &signals[i];
+	const struct signal *s = &signals[i];
 
 	if (s->which != which)
 	    continue;
@@ -377,60 +620,59 @@
     }
 }
 
-static void do_bindings(struct binding *bindings, int num_bindings)
+static void do_bindings(const struct binding *bindings, int num_bindings)
 {
     int i;
 
     for (i = 0; i < num_bindings; i++) {
-	struct binding *b = &bindings[i];
-	static char *str = NULL;
+	const struct binding *b = &bindings[i];
+	char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
 
-	str = G_realloc(str, strlen(b->var) + strlen(b->val) + 2);
 	sprintf(str, "%s=%s", b->var, b->val);
 	putenv(str);
     }
 }
 
-static int do_spawn(const char *command)
+static int do_spawn(struct spawn *sp, const char *command)
 {
     int status = -1;
     pid_t pid;
 
-    if (!do_signals(signals, num_signals, SST_PRE))
+    if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
 	return status;
 
     pid = fork();
     if (pid < 0) {
 	G_warning(_("Unable to create a new process"));
-	undo_signals(signals, num_signals, SST_PRE);
+	undo_signals(sp->signals, sp->num_signals, SST_PRE);
 
 	return status;
     }
 
     if (pid == 0) {
-	if (!undo_signals(signals, num_signals, SST_PRE))
+	if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
 	    _exit(127);
 
-	if (!do_signals(signals, num_signals, SST_CHILD))
+	if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
 	    _exit(127);
 
-	if (directory)
-	    if (chdir(directory) < 0) {
-		G_warning(_("Unable to change directory to %s"), directory);
+	if (sp->directory)
+	    if (chdir(sp->directory) < 0) {
+		G_warning(_("Unable to change directory to %s"), sp->directory);
 		_exit(127);
 	    }
 
-	do_redirects(redirects, num_redirects);
-	do_bindings(bindings, num_bindings);
+	do_redirects(sp->redirects, sp->num_redirects);
+	do_bindings(sp->bindings, sp->num_bindings);
 
-	execvp(command, (char **)args);
+	execvp(command, (char **)sp->args);
 	G_warning(_("Unable to execute command"));
 	_exit(127);
     }
 
-    do_signals(signals, num_signals, SST_POST);
+    do_signals(sp->signals, sp->num_signals, SST_POST);
 
-    if (background)
+    if (sp->background)
 	status = (int)pid;
     else {
 	pid_t n;
@@ -443,171 +685,158 @@
 	    status = -1;
     }
 
-    undo_signals(signals, num_signals, SST_POST);
-    undo_signals(signals, num_signals, SST_PRE);
+    undo_signals(sp->signals, sp->num_signals, SST_POST);
+    undo_signals(sp->signals, sp->num_signals, SST_PRE);
 
     return status;
 }
 
 #endif /* __MINGW32__ */
 
-static void begin_spawn(void)
+static void begin_spawn(struct spawn *sp)
 {
-    num_args = 0;
-    num_redirects = 0;
-    num_signals = 0;
-    num_bindings = 0;
-    background = 0;
-    directory = NULL;
+    sp->num_args = 0;
+    sp->num_redirects = 0;
+    sp->num_signals = 0;
+    sp->num_bindings = 0;
+    sp->background = 0;
+    sp->directory = NULL;
 }
 
 #define NEXT_ARG(var, type) ((type) *(var)++)
 
-static void parse_argvec(const char **va)
+static void parse_argvec(struct spawn *sp, const char **va)
 {
     for (;;) {
 	const char *arg = NEXT_ARG(va, const char *);
 	const char *var, *val;
 
-	switch ((int)arg) {
-	case 0:
-	    args[num_args++] = NULL;
+	if (!arg) {
+	    sp->args[sp->num_args++] = NULL;
 	    break;
-	case ((int)SF_REDIRECT_FILE):
-	    redirects[num_redirects].dst_fd = NEXT_ARG(va, int);
+	}
+	else if (arg == SF_REDIRECT_FILE) {
+	    sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
 
-	    redirects[num_redirects].src_fd = -1;
-	    redirects[num_redirects].mode = NEXT_ARG(va, int);
-	    redirects[num_redirects].file = NEXT_ARG(va, const char *);
+	    sp->redirects[sp->num_redirects].src_fd = -1;
+	    sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
+	    sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
 
-	    num_redirects++;
-	    break;
-	case ((int)SF_REDIRECT_DESCRIPTOR):
-	    redirects[num_redirects].dst_fd = NEXT_ARG(va, int);
-	    redirects[num_redirects].src_fd = NEXT_ARG(va, int);
+	    sp->num_redirects++;
+	}
+	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);
 
-	    redirects[num_redirects].file = NULL;
-	    num_redirects++;
-	    break;
-	case ((int)SF_CLOSE_DESCRIPTOR):
-	    redirects[num_redirects].dst_fd = NEXT_ARG(va, int);
+	    sp->redirects[sp->num_redirects].file = NULL;
+	    sp->num_redirects++;
+	}
+	else if (arg == SF_CLOSE_DESCRIPTOR) {
+	    sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
 
-	    redirects[num_redirects].src_fd = -1;
-	    redirects[num_redirects].file = NULL;
-	    num_redirects++;
-	    break;
-	case ((int)SF_SIGNAL):
-	    signals[num_signals].which = NEXT_ARG(va, int);
-	    signals[num_signals].action = NEXT_ARG(va, int);
-	    signals[num_signals].signum = NEXT_ARG(va, int);
+	    sp->redirects[sp->num_redirects].src_fd = -1;
+	    sp->redirects[sp->num_redirects].file = NULL;
+	    sp->num_redirects++;
+	}
+	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);
 
-	    signals[num_signals].valid = 0;
-	    num_signals++;
-	    break;
-	case ((int)SF_VARIABLE):
+	    sp->signals[sp->num_signals].valid = 0;
+	    sp->num_signals++;
+	}
+	else if (arg == SF_VARIABLE) {
 	    var = NEXT_ARG(va, const char *);
 
 	    val = getenv(var);
-	    args[num_args++] = val ? val : "";
-	    break;
-	case ((int)SF_BINDING):
-	    bindings[num_bindings].var = NEXT_ARG(va, const char *);
-	    bindings[num_bindings].val = NEXT_ARG(va, const char *);
+	    sp->args[sp->num_args++] = val ? val : "";
+	}
+	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 *);
 
-	    num_bindings++;
-	    break;
-	case ((int)SF_BACKGROUND):
-	    background = 1;
-	    break;
-	case ((int)SF_DIRECTORY):
-	    directory = NEXT_ARG(va, const char *);
+	    sp->num_bindings++;
+	}
+	else if (arg == SF_BACKGROUND) {
+	    sp->background = 1;
+	}
+	else if (arg == SF_DIRECTORY) {
+	    sp->directory = NEXT_ARG(va, const char *);
 
-	    break;
-	case ((int)SF_ARGVEC):
-	    parse_argvec(NEXT_ARG(va, const char **));
-
-	    break;
-	default:
-	    args[num_args++] = arg;
-	    break;
 	}
-
-	if (!arg)
-	    break;
+	else if (arg == SF_ARGVEC) {
+	    parse_argvec(sp, NEXT_ARG(va, const char **));
+	}
+	else
+	    sp->args[sp->num_args++] = arg;
     }
 }
 
-static void parse_arglist(va_list va)
+static void parse_arglist(struct spawn *sp, va_list va)
 {
     for (;;) {
 	const char *arg = va_arg(va, const char *);
 	const char *var, *val;
 
-	switch ((int)arg) {
-	case 0:
-	    args[num_args++] = NULL;
+	if (!arg) {
+	    sp->args[sp->num_args++] = NULL;
 	    break;
-	case ((int)SF_REDIRECT_FILE):
-	    redirects[num_redirects].dst_fd = va_arg(va, int);
+	}
+	else if (arg == SF_REDIRECT_FILE) {
+	    sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
 
-	    redirects[num_redirects].src_fd = -1;
-	    redirects[num_redirects].mode = va_arg(va, int);
-	    redirects[num_redirects].file = va_arg(va, const char *);
+	    sp->redirects[sp->num_redirects].src_fd = -1;
+	    sp->redirects[sp->num_redirects].mode = va_arg(va, int);
+	    sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
 
-	    num_redirects++;
-	    break;
-	case ((int)SF_REDIRECT_DESCRIPTOR):
-	    redirects[num_redirects].dst_fd = va_arg(va, int);
-	    redirects[num_redirects].src_fd = va_arg(va, int);
+	    sp->num_redirects++;
+	}
+	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);
 
-	    redirects[num_redirects].file = NULL;
-	    num_redirects++;
-	    break;
-	case ((int)SF_CLOSE_DESCRIPTOR):
-	    redirects[num_redirects].dst_fd = va_arg(va, int);
+	    sp->redirects[sp->num_redirects].file = NULL;
+	    sp->num_redirects++;
+	}
+	else if (arg == SF_CLOSE_DESCRIPTOR) {
+	    sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
 
-	    redirects[num_redirects].src_fd = -1;
-	    redirects[num_redirects].file = NULL;
-	    num_redirects++;
-	    break;
-	case ((int)SF_SIGNAL):
-	    signals[num_signals].which = va_arg(va, int);
-	    signals[num_signals].action = va_arg(va, int);
-	    signals[num_signals].signum = va_arg(va, int);
+	    sp->redirects[sp->num_redirects].src_fd = -1;
+	    sp->redirects[sp->num_redirects].file = NULL;
+	    sp->num_redirects++;
+	}
+	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);
 
-	    signals[num_signals].valid = 0;
-	    num_signals++;
-	    break;
-	case ((int)SF_VARIABLE):
+	    sp->signals[sp->num_signals].valid = 0;
+	    sp->num_signals++;
+	}
+	else if (arg == SF_VARIABLE) {
 	    var = va_arg(va, char *);
 
 	    val = getenv(var);
-	    args[num_args++] = val ? val : "";
-	    break;
-	case ((int)SF_BINDING):
-	    bindings[num_bindings].var = va_arg(va, const char *);
-	    bindings[num_bindings].val = va_arg(va, const char *);
+	    sp->args[sp->num_args++] = val ? val : "";
+	}
+	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 *);
 
-	    num_bindings++;
-	    break;
-	case ((int)SF_BACKGROUND):
-	    background = 1;
-	    break;
-	case ((int)SF_DIRECTORY):
-	    directory = va_arg(va, const char *);
-
-	    break;
-	case ((int)SF_ARGVEC):
-	    parse_argvec(va_arg(va, const char **));
-
-	    break;
-	default:
-	    args[num_args++] = arg;
-	    break;
+	    sp->num_bindings++;
 	}
-
-	if (!arg)
-	    break;
+	else if (arg == SF_BACKGROUND) {
+	    sp->background = 1;
+	}
+	else if (arg == SF_DIRECTORY) {
+	    sp->directory = va_arg(va, const char *);
+	}
+	else if (arg == SF_ARGVEC) {
+	    parse_argvec(sp, va_arg(va, const char **));
+	}
+	else
+	    sp->args[sp->num_args++] = arg;
     }
 }
 
@@ -623,11 +852,13 @@
  */
 int G_vspawn_ex(const char *command, const char **args)
 {
-    begin_spawn();
+    struct spawn sp;
 
-    parse_argvec(args);
+    begin_spawn(&sp);
 
-    return do_spawn(command);
+    parse_argvec(&sp, args);
+
+    return do_spawn(&sp, command);
 }
 
 /**
@@ -642,13 +873,54 @@
 
 int G_spawn_ex(const char *command, ...)
 {
+    struct spawn sp;
     va_list va;
 
-    begin_spawn();
+    begin_spawn(&sp);
 
     va_start(va, command);
-    parse_arglist(va);
+    parse_arglist(&sp, va);
     va_end(va);
 
-    return do_spawn(command);
+    return do_spawn(&sp, command);
 }
+
+/**
+ * \brief Spawn new process based on <b>command</b>.
+ *
+ * \param[in] command
+ * \return -1 on error
+ * \return process status on success
+ */
+
+int G_spawn(const char *command, ...)
+{
+    const char *args[MAX_ARGS];
+    int num_args = 0, i;
+    va_list va;
+    int status = -1;
+
+    va_start(va, command);
+
+    for (i = 0; ; i++) {
+	const char *arg = va_arg(va, const char *);
+	args[num_args++] = arg;
+	if (!arg)
+	    break;
+    }
+
+    va_end(va);
+
+    status = G_spawn_ex(
+	command,
+#ifndef __MINGW32__
+	SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
+	SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
+	SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
+#endif
+	SF_ARGVEC, args,
+	NULL);
+
+    return status;
+}
+



More information about the grass-commit mailing list