00001
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <signal.h>
00021 #include <stdarg.h>
00022 #include <unistd.h>
00023 #include <fcntl.h>
00024 #include <errno.h>
00025 #include <sys/types.h>
00026
00027 #ifndef __MINGW32__
00028 #include <sys/wait.h>
00029 #else
00030 #include <windows.h>
00031 #endif
00032 #include <grass/config.h>
00033 #include <grass/gis.h>
00034 #include <grass/glocale.h>
00035 #include <grass/spawn.h>
00036
00044 #define MAX_ARGS 256
00045 #define MAX_BINDINGS 256
00046 #define MAX_SIGNALS 32
00047 #define MAX_REDIRECTS 32
00048
00049
00061 struct redirect
00062 {
00063 int dst_fd;
00064 int src_fd;
00065 const char *file;
00066 int mode;
00067 };
00068
00069 struct signal
00070 {
00071 int which;
00072 int action;
00073 int signum;
00074 int valid;
00075 #ifndef __MINGW32__
00076 struct sigaction old_act;
00077 sigset_t old_mask;
00078 #endif
00079 };
00080
00081 struct binding
00082 {
00083 const char *var;
00084 const char *val;
00085 };
00086
00087 struct spawn
00088 {
00089 const char *args[MAX_ARGS];
00090 int num_args;
00091 struct redirect redirects[MAX_REDIRECTS];
00092 int num_redirects;
00093 struct signal signals[MAX_SIGNALS];
00094 int num_signals;
00095 struct binding bindings[MAX_BINDINGS];
00096 int num_bindings;
00097 int background;
00098 const char *directory;
00099 };
00100
00101 static void parse_arglist(struct spawn *sp, va_list va);
00102 static void parse_argvec(struct spawn *sp, const char **va);
00103
00104 #ifdef __MINGW32__
00105
00106 struct buffer {
00107 char *str;
00108 size_t len;
00109 size_t size;
00110 };
00111
00112 static const int INCREMENT = 50;
00113
00114 static void clear(struct buffer *b)
00115 {
00116 b->len = 0;
00117 b->str[b->len] = '\0';
00118 }
00119
00120 static void init(struct buffer *b)
00121 {
00122 b->str = G_malloc(1);
00123 b->size = 1;
00124 clear(b);
00125 }
00126
00127 static char *release(struct buffer *b)
00128 {
00129 char *p = b->str;
00130
00131 b->str = NULL;
00132 b->size = 0;
00133 b->len = 0;
00134
00135 return p;
00136 }
00137
00138 static void finish(struct buffer *b)
00139 {
00140 if (b->str)
00141 G_free(b->str);
00142 release(b);
00143 }
00144
00145 static void ensure(struct buffer *b, size_t n)
00146 {
00147 if (b->size <= b->len + n + 1) {
00148 b->size = b->len + n + INCREMENT;
00149 b->str = G_realloc(b->str, b->size);
00150 }
00151 }
00152
00153 static void append(struct buffer *b, const char *str)
00154 {
00155 size_t n = strlen(str);
00156
00157 ensure(b, n);
00158 memcpy(&b->str[b->len], str, n);
00159 b->len += n;
00160 b->str[b->len] = '\0';
00161 }
00162
00163 static void append_char(struct buffer *b, char c)
00164 {
00165 ensure(b, 1);
00166 b->str[b->len] = c;
00167 b->len++;
00168 b->str[b->len] = '\0';
00169 }
00170
00171 static void escape_arg(struct buffer *result, const char *arg)
00172 {
00173 struct buffer buf;
00174 int quote, j;
00175
00176 init(&buf);
00177
00178 quote = arg[0] == '\0' || strchr(arg, ' ') || strchr(arg, '\t');
00179
00180 if (quote)
00181 append_char(result, '\"');
00182
00183 for (j = 0; arg[j]; j++) {
00184 int c = arg[j];
00185 int k;
00186
00187 switch (c) {
00188 case '\\':
00189 append_char(&buf, '\\');
00190 break;
00191 case '\"':
00192 for (k = 0; k < buf.len; k++)
00193 append(result, "\\\\");
00194 clear(&buf);
00195 append(result, "\\\"");
00196 break;
00197 default:
00198 if (buf.len > 0) {
00199 append(result, buf.str);
00200 clear(&buf);
00201 }
00202 append_char(result, c);
00203 }
00204 }
00205
00206 if (buf.len > 0)
00207 append(result, buf.str);
00208
00209 if (quote) {
00210 append(result, buf.str);
00211 append_char(result, '\"');
00212 }
00213
00214 finish(&buf);
00215 }
00216
00217 static char *check_program(const char *pgm, const char *dir, const char *ext)
00218 {
00219 char pathname[GPATH_MAX];
00220
00221 sprintf(pathname, "%s%s%s%s", dir, *dir ? "\\" : "", pgm, ext);
00222 return access(pathname, 0) == 0
00223 ? G_store(pathname)
00224 : NULL;
00225 }
00226
00227 static char *find_program_ext(const char *pgm, const char *dir, char **pathext)
00228 {
00229 char *result;
00230 int i;
00231
00232 if (result = check_program(pgm, dir, ""), result)
00233 return result;
00234
00235 for (i = 0; pathext[i]; i++) {
00236 const char *ext = pathext[i];
00237 if (result = check_program(pgm, dir, ext), result)
00238 return result;
00239 }
00240
00241 return NULL;
00242 }
00243
00244 static char *find_program_dir_ext(const char *pgm, char **path, char **pathext)
00245 {
00246 char *result = NULL;
00247 int i;
00248
00249 if (strchr(pgm, '\\') || strchr(pgm, '/')) {
00250 if (result = find_program_ext(pgm, "", pathext), result)
00251 return result;
00252 }
00253 else {
00254 if (result = find_program_ext(pgm, ".", pathext), result)
00255 return result;
00256
00257 for (i = 0; path[i]; i++) {
00258 const char *dir = path[i];
00259 if (result = find_program_ext(pgm, dir, pathext), result)
00260 return result;
00261 }
00262 }
00263
00264 return NULL;
00265 }
00266
00267 static char *find_program(const char *pgm)
00268 {
00269 char **path = G_tokenize(getenv("PATH"), ";");
00270 char **pathext = G_tokenize(getenv("PATHEXT"), ";");
00271 char *result = find_program_dir_ext(pgm, path, pathext);
00272 G_free_tokens(path);
00273 G_free_tokens(pathext);
00274 return result;
00275 }
00276
00277 static char *make_command_line(int shell, const char *cmd, const char **argv)
00278 {
00279 struct buffer result;
00280 int i;
00281
00282 init(&result);
00283
00284 if (shell) {
00285 const char *comspec = getenv("COMSPEC");
00286 append(&result, comspec ? comspec : "cmd.exe");
00287 append(&result, " /c \"");
00288 escape_arg(&result, cmd);
00289 }
00290
00291 for (i = shell ? 1 : 0; argv[i]; i++) {
00292 if (result.len > 0)
00293 append_char(&result, ' ');
00294 escape_arg(&result, argv[i]);
00295 }
00296
00297 append(&result, "\"");
00298
00299 return release(&result);
00300 }
00301
00302 static char *make_environment(const char **envp)
00303 {
00304 struct buffer result;
00305 int i;
00306
00307 init(&result);
00308
00309 for (i = 0; envp[i]; i++) {
00310 const char *env = envp[i];
00311
00312 append(&result, env);
00313 append_char(&result, '\0');
00314 }
00315
00316 return release(&result);
00317 }
00318
00319 static HANDLE get_handle(int fd)
00320 {
00321 HANDLE h1, h2;
00322
00323 if (fd < 0)
00324 return INVALID_HANDLE_VALUE;
00325
00326 h1 = (HANDLE) _get_osfhandle(fd);
00327 if (!DuplicateHandle(GetCurrentProcess(), h1,
00328 GetCurrentProcess(), &h2,
00329 0, TRUE, DUPLICATE_SAME_ACCESS))
00330 return INVALID_HANDLE_VALUE;
00331
00332 return h2;
00333 }
00334
00335 static int win_spawn(const char *cmd, const char **argv, const char **envp,
00336 const char *cwd, HANDLE handles[3], int background,
00337 int shell)
00338 {
00339 char *args = make_command_line(shell, cmd, argv);
00340 char *env = make_environment(envp);
00341 char *program = shell ? NULL : find_program(cmd);
00342 STARTUPINFO si;
00343 PROCESS_INFORMATION pi;
00344 BOOL result;
00345 DWORD exitcode;
00346
00347 if (!shell) {
00348 G_debug(3, "win_spawn: program = %s", program);
00349
00350 if (!program) {
00351 G_free(args);
00352 G_free(env);
00353 return -1;
00354 }
00355 }
00356
00357 G_debug(3, "win_spawn: args = %s", args);
00358
00359 memset(&si, 0, sizeof(si));
00360 si.cb = sizeof(si);
00361
00362 si.dwFlags |= STARTF_USESTDHANDLES;
00363 si.hStdInput = handles[0];
00364 si.hStdOutput = handles[1];
00365 si.hStdError = handles[2];
00366
00367 result = CreateProcess(
00368 program,
00369 args,
00370 NULL,
00371 NULL,
00372 1,
00373 0,
00374 env,
00375 cwd,
00376 &si,
00377 &pi
00378 );
00379
00380 G_free(args);
00381 G_free(env);
00382 G_free(program);
00383
00384 if (!result) {
00385 G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
00386 return -1;
00387 }
00388
00389 if (!background) {
00390 WaitForSingleObject(pi.hProcess, INFINITE);
00391 if (!GetExitCodeProcess(pi.hProcess, &exitcode))
00392 return -1;
00393 return (int) exitcode;
00394 }
00395
00396 return pi.dwProcessId;
00397 }
00398
00399 static void do_redirects(struct redirect *redirects, int num_redirects, HANDLE handles[3])
00400 {
00401 int i;
00402
00403 for (i = 0; i < 3; i++)
00404 handles[i] = get_handle(i);
00405
00406 for (i = 0; i < num_redirects; i++) {
00407 struct redirect *r = &redirects[i];
00408
00409 if (r->dst_fd < 0 || r->dst_fd > 2) {
00410 G_warning(_("G_spawn: unable to redirect descriptor %d"), r->dst_fd);
00411 continue;
00412 }
00413
00414 if (r->file) {
00415 r->src_fd = open(r->file, r->mode, 0666);
00416
00417 if (r->src_fd < 0) {
00418 G_warning(_("G_spawn: unable to open file %s"), r->file);
00419 _exit(127);
00420 }
00421
00422 handles[r->dst_fd] = get_handle(r->src_fd);
00423
00424 close(r->src_fd);
00425
00426 }
00427 else if (r->src_fd >= 0) {
00428 handles[r->dst_fd] = get_handle(r->src_fd);
00429 }
00430 else
00431 handles[r->dst_fd] = INVALID_HANDLE_VALUE;
00432 }
00433 }
00434
00435 static void add_binding(const char **env, int *pnum, const struct binding *b)
00436 {
00437 char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00438 int n = *pnum;
00439 int i;
00440
00441 sprintf(str, "%s=%s", b->var, b->val);
00442
00443 for (i = 0; i < n; i++)
00444 if (G_strcasecmp(env[i], b->var) == 0) {
00445 env[i] = str;
00446 return;
00447 }
00448
00449 env[n++] = str;
00450 *pnum = n;
00451 }
00452
00453 static const char **do_bindings(const struct binding *bindings, int num_bindings)
00454 {
00455 const char **newenv;
00456 int i, n;
00457
00458 for (i = 0; _environ[i]; i++)
00459 ;
00460 n = i;
00461
00462 newenv = G_malloc((num_bindings + n + 1) * sizeof(char *));
00463
00464 for (i = 0; i < n; i++)
00465 newenv[i] = _environ[i];
00466
00467 for (i = 0; i < num_bindings; i++)
00468 add_binding(newenv, &n, &bindings[i]);
00469
00470 newenv[num_bindings + n] = NULL;
00471
00472 return newenv;
00473 }
00474
00475 static int do_spawn(struct spawn *sp, const char *command)
00476 {
00477 HANDLE handles[3];
00478 const char **env;
00479 int status;
00480
00481 do_redirects(sp->redirects, sp->num_redirects, handles);
00482 env = do_bindings(sp->bindings, sp->num_bindings);
00483
00484 status = win_spawn(command, sp->args, env, sp->directory, handles, sp->background, 1);
00485
00486 if (!sp->background && status < 0)
00487 G_warning(_("Unable to execute command"));
00488
00489 return status;
00490 }
00491
00492 #else
00493
00494 static int undo_signals(const struct signal *signals, int num_signals, int which)
00495 {
00496 int error = 0;
00497 int i;
00498
00499 for (i = num_signals - 1; i >= 0; i--) {
00500 const struct signal *s = &signals[i];
00501
00502 if (s->which != which)
00503 continue;
00504
00505 if (!s->valid)
00506 continue;
00507
00508 switch (s->action) {
00509 case SSA_IGNORE:
00510 case SSA_DEFAULT:
00511 if (sigaction(s->signum, &s->old_act, NULL) < 0) {
00512 G_warning(_("G_spawn: unable to restore signal %d"),
00513 s->signum);
00514 error = 1;
00515 }
00516 break;
00517 case SSA_BLOCK:
00518 case SSA_UNBLOCK:
00519 if (sigprocmask(SIG_UNBLOCK, &s->old_mask, NULL) < 0) {
00520 G_warning(_("G_spawn: unable to restore signal %d"),
00521 s->signum);
00522 error = 1;
00523 }
00524 break;
00525 }
00526 }
00527
00528 return !error;
00529 }
00530
00531 static int do_signals(struct signal *signals, int num_signals, int which)
00532 {
00533 struct sigaction act;
00534 sigset_t mask;
00535 int error = 0;
00536 int i;
00537
00538 sigemptyset(&act.sa_mask);
00539 act.sa_flags = SA_RESTART;
00540
00541 for (i = 0; i < num_signals; i++) {
00542 struct signal *s = &signals[i];
00543
00544 if (s->which != which)
00545 continue;
00546
00547 switch (s->action) {
00548 case SSA_IGNORE:
00549 act.sa_handler = SIG_IGN;
00550 if (sigaction(s->signum, &act, &s->old_act) < 0) {
00551 G_warning(_("G_spawn: unable to reset signal %d"), s->signum);
00552 error = 1;
00553 }
00554 else
00555 s->valid = 1;
00556 break;
00557 case SSA_DEFAULT:
00558 act.sa_handler = SIG_DFL;
00559 if (sigaction(s->signum, &act, &s->old_act) < 0) {
00560 G_warning(_("G_spawn: unable to ignore signal %d"),
00561 s->signum);
00562 error = 1;
00563 }
00564 else
00565 s->valid = 1;
00566 break;
00567 case SSA_BLOCK:
00568 sigemptyset(&mask);
00569 sigaddset(&mask, s->signum);
00570 if (sigprocmask(SIG_BLOCK, &mask, &s->old_mask) < 0) {
00571 G_warning(_("G_spawn: unable to block signal %d"), s->signum);
00572 error = 1;
00573 }
00574 break;
00575 case SSA_UNBLOCK:
00576 sigemptyset(&mask);
00577 sigaddset(&mask, s->signum);
00578 if (sigprocmask(SIG_UNBLOCK, &mask, &s->old_mask) < 0) {
00579 G_warning(_("G_spawn: unable to unblock signal %d"),
00580 s->signum);
00581 error = 1;
00582 }
00583 else
00584 s->valid = 1;
00585 break;
00586 }
00587 }
00588
00589 return !error;
00590 }
00591
00592 static void do_redirects(struct redirect *redirects, int num_redirects)
00593 {
00594 int i;
00595
00596 for (i = 0; i < num_redirects; i++) {
00597 struct redirect *r = &redirects[i];
00598
00599 if (r->file) {
00600 r->src_fd = open(r->file, r->mode, 0666);
00601
00602 if (r->src_fd < 0) {
00603 G_warning(_("G_spawn: unable to open file %s"), r->file);
00604 _exit(127);
00605 }
00606
00607 if (dup2(r->src_fd, r->dst_fd) < 0) {
00608 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00609 r->src_fd, r->dst_fd);
00610 _exit(127);
00611 }
00612
00613 close(r->src_fd);
00614 }
00615 else if (r->src_fd >= 0) {
00616 if (dup2(r->src_fd, r->dst_fd) < 0) {
00617 G_warning(_("G_spawn: unable to duplicate descriptor %d to %d"),
00618 r->src_fd, r->dst_fd);
00619 _exit(127);
00620 }
00621 }
00622 else
00623 close(r->dst_fd);
00624 }
00625 }
00626
00627 static void do_bindings(const struct binding *bindings, int num_bindings)
00628 {
00629 int i;
00630
00631 for (i = 0; i < num_bindings; i++) {
00632 const struct binding *b = &bindings[i];
00633 char *str = G_malloc(strlen(b->var) + strlen(b->val) + 2);
00634
00635 sprintf(str, "%s=%s", b->var, b->val);
00636 putenv(str);
00637 }
00638 }
00639
00640 static int do_spawn(struct spawn *sp, const char *command)
00641 {
00642 int status = -1;
00643 pid_t pid;
00644
00645 if (!do_signals(sp->signals, sp->num_signals, SST_PRE))
00646 return status;
00647
00648 pid = fork();
00649 if (pid < 0) {
00650 G_warning(_("Unable to create a new process"));
00651 undo_signals(sp->signals, sp->num_signals, SST_PRE);
00652
00653 return status;
00654 }
00655
00656 if (pid == 0) {
00657 if (!undo_signals(sp->signals, sp->num_signals, SST_PRE))
00658 _exit(127);
00659
00660 if (!do_signals(sp->signals, sp->num_signals, SST_CHILD))
00661 _exit(127);
00662
00663 if (sp->directory)
00664 if (chdir(sp->directory) < 0) {
00665 G_warning(_("Unable to change directory to %s"), sp->directory);
00666 _exit(127);
00667 }
00668
00669 do_redirects(sp->redirects, sp->num_redirects);
00670 do_bindings(sp->bindings, sp->num_bindings);
00671
00672 execvp(command, (char **)sp->args);
00673 G_warning(_("Unable to execute command"));
00674 _exit(127);
00675 }
00676
00677 do_signals(sp->signals, sp->num_signals, SST_POST);
00678
00679 if (sp->background)
00680 status = (int)pid;
00681 else {
00682 pid_t n;
00683
00684 do
00685 n = waitpid(pid, &status, 0);
00686 while (n == (pid_t) - 1 && errno == EINTR);
00687
00688 if (n != pid)
00689 status = -1;
00690 else {
00691 if (WIFEXITED(status))
00692 status = WEXITSTATUS(status);
00693 else if (WIFSIGNALED(status))
00694 status = WTERMSIG(status);
00695 else
00696 status = -0x100;
00697 }
00698 }
00699
00700 undo_signals(sp->signals, sp->num_signals, SST_POST);
00701 undo_signals(sp->signals, sp->num_signals, SST_PRE);
00702
00703 return status;
00704 }
00705
00706 #endif
00707
00708 static void begin_spawn(struct spawn *sp)
00709 {
00710 sp->num_args = 0;
00711 sp->num_redirects = 0;
00712 sp->num_signals = 0;
00713 sp->num_bindings = 0;
00714 sp->background = 0;
00715 sp->directory = NULL;
00716 }
00717
00718 #define NEXT_ARG(var, type) ((type) (ssize_t) *(var)++)
00719
00720 static void parse_argvec(struct spawn *sp, const char **va)
00721 {
00722 for (;;) {
00723 const char *arg = NEXT_ARG(va, const char *);
00724 const char *var, *val;
00725
00726 if (!arg) {
00727 sp->args[sp->num_args++] = NULL;
00728 break;
00729 }
00730 else if (arg == SF_REDIRECT_FILE) {
00731 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00732
00733 sp->redirects[sp->num_redirects].src_fd = -1;
00734 sp->redirects[sp->num_redirects].mode = NEXT_ARG(va, int);
00735 sp->redirects[sp->num_redirects].file = NEXT_ARG(va, const char *);
00736
00737 sp->num_redirects++;
00738 }
00739 else if (arg == SF_REDIRECT_DESCRIPTOR) {
00740 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00741 sp->redirects[sp->num_redirects].src_fd = NEXT_ARG(va, int);
00742
00743 sp->redirects[sp->num_redirects].file = NULL;
00744 sp->num_redirects++;
00745 }
00746 else if (arg == SF_CLOSE_DESCRIPTOR) {
00747 sp->redirects[sp->num_redirects].dst_fd = NEXT_ARG(va, int);
00748
00749 sp->redirects[sp->num_redirects].src_fd = -1;
00750 sp->redirects[sp->num_redirects].file = NULL;
00751 sp->num_redirects++;
00752 }
00753 else if (arg == SF_SIGNAL) {
00754 sp->signals[sp->num_signals].which = NEXT_ARG(va, int);
00755 sp->signals[sp->num_signals].action = NEXT_ARG(va, int);
00756 sp->signals[sp->num_signals].signum = NEXT_ARG(va, int);
00757
00758 sp->signals[sp->num_signals].valid = 0;
00759 sp->num_signals++;
00760 }
00761 else if (arg == SF_VARIABLE) {
00762 var = NEXT_ARG(va, const char *);
00763
00764 val = getenv(var);
00765 sp->args[sp->num_args++] = val ? val : "";
00766 }
00767 else if (arg == SF_BINDING) {
00768 sp->bindings[sp->num_bindings].var = NEXT_ARG(va, const char *);
00769 sp->bindings[sp->num_bindings].val = NEXT_ARG(va, const char *);
00770
00771 sp->num_bindings++;
00772 }
00773 else if (arg == SF_BACKGROUND) {
00774 sp->background = 1;
00775 }
00776 else if (arg == SF_DIRECTORY) {
00777 sp->directory = NEXT_ARG(va, const char *);
00778
00779 }
00780 else if (arg == SF_ARGVEC) {
00781 parse_argvec(sp, NEXT_ARG(va, const char **));
00782 }
00783 else
00784 sp->args[sp->num_args++] = arg;
00785 }
00786 }
00787
00788 static void parse_arglist(struct spawn *sp, va_list va)
00789 {
00790 for (;;) {
00791 const char *arg = va_arg(va, const char *);
00792 const char *var, *val;
00793
00794 if (!arg) {
00795 sp->args[sp->num_args++] = NULL;
00796 break;
00797 }
00798 else if (arg == SF_REDIRECT_FILE) {
00799 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00800
00801 sp->redirects[sp->num_redirects].src_fd = -1;
00802 sp->redirects[sp->num_redirects].mode = va_arg(va, int);
00803 sp->redirects[sp->num_redirects].file = va_arg(va, const char *);
00804
00805 sp->num_redirects++;
00806 }
00807 else if (arg == SF_REDIRECT_DESCRIPTOR) {
00808 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00809 sp->redirects[sp->num_redirects].src_fd = va_arg(va, int);
00810
00811 sp->redirects[sp->num_redirects].file = NULL;
00812 sp->num_redirects++;
00813 }
00814 else if (arg == SF_CLOSE_DESCRIPTOR) {
00815 sp->redirects[sp->num_redirects].dst_fd = va_arg(va, int);
00816
00817 sp->redirects[sp->num_redirects].src_fd = -1;
00818 sp->redirects[sp->num_redirects].file = NULL;
00819 sp->num_redirects++;
00820 }
00821 else if (arg == SF_SIGNAL) {
00822 sp->signals[sp->num_signals].which = va_arg(va, int);
00823 sp->signals[sp->num_signals].action = va_arg(va, int);
00824 sp->signals[sp->num_signals].signum = va_arg(va, int);
00825
00826 sp->signals[sp->num_signals].valid = 0;
00827 sp->num_signals++;
00828 }
00829 else if (arg == SF_VARIABLE) {
00830 var = va_arg(va, char *);
00831
00832 val = getenv(var);
00833 sp->args[sp->num_args++] = val ? val : "";
00834 }
00835 else if (arg == SF_BINDING) {
00836 sp->bindings[sp->num_bindings].var = va_arg(va, const char *);
00837 sp->bindings[sp->num_bindings].val = va_arg(va, const char *);
00838
00839 sp->num_bindings++;
00840 }
00841 else if (arg == SF_BACKGROUND) {
00842 sp->background = 1;
00843 }
00844 else if (arg == SF_DIRECTORY) {
00845 sp->directory = va_arg(va, const char *);
00846 }
00847 else if (arg == SF_ARGVEC) {
00848 parse_argvec(sp, va_arg(va, const char **));
00849 }
00850 else
00851 sp->args[sp->num_args++] = arg;
00852 }
00853 }
00854
00865 int G_vspawn_ex(const char *command, const char **args)
00866 {
00867 struct spawn sp;
00868
00869 begin_spawn(&sp);
00870
00871 parse_argvec(&sp, args);
00872
00873 return do_spawn(&sp, command);
00874 }
00875
00886 int G_spawn_ex(const char *command, ...)
00887 {
00888 struct spawn sp;
00889 va_list va;
00890
00891 begin_spawn(&sp);
00892
00893 va_start(va, command);
00894 parse_arglist(&sp, va);
00895 va_end(va);
00896
00897 return do_spawn(&sp, command);
00898 }
00899
00908 int G_spawn(const char *command, ...)
00909 {
00910 const char *args[MAX_ARGS];
00911 int num_args = 0, i;
00912 va_list va;
00913 int status = -1;
00914
00915 va_start(va, command);
00916
00917 for (i = 0; ; i++) {
00918 const char *arg = va_arg(va, const char *);
00919 args[num_args++] = arg;
00920 if (!arg)
00921 break;
00922 }
00923
00924 va_end(va);
00925
00926 status = G_spawn_ex(
00927 command,
00928 #ifndef __MINGW32__
00929 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGINT,
00930 SF_SIGNAL, SST_PRE, SSA_IGNORE, SIGQUIT,
00931 SF_SIGNAL, SST_PRE, SSA_BLOCK, SIGCHLD,
00932 #endif
00933 SF_ARGVEC, args,
00934 NULL);
00935
00936 return status;
00937 }
00938