home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari FTP
/
ATARI_FTP_0693.zip
/
ATARI_FTP_0693
/
Mint
/
mntlib32.zoo
/
spawn.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-25
|
7KB
|
335 lines
/*
89/03/02: ERS: added the "mode" argument for MS-DOS/Unix
compatibility. Added prototypes for GNU C.
fixed spawnve: the original didn't pass the command tail
correctly, nor did it handle errno right. Also, this version
passes args in the environment as well as the command line,
using the ARGV= mechanism supported by crt0.s
Written 89/01/10 by ERS. Original version Copyright (c) 1988 by
Memorial University of Newfoundland. This version is based upon
that original, but is substantially different. (In fact, there
probably isn't a single line of the original left.)
Adapted 90/06/25 by ERS to MiNT.
08 Apr 93 hohmuth
added support for ARGV standard extension allowing empty arguments
uo, 3.5.93, throw away some static characterarrays (path[] and
cmd[]).
*/
#include <stdarg.h>
#include <process.h>
#include <param.h>
#include <errno.h>
#include <osbind.h>
#include <mintbind.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <unistd.h>
#include "lib.h"
#define TOS_ARGS 126
extern char **environ;
extern int __mint;
int
_spawnve(mode, _path, argv, envp)
int mode;
char *_path;
char **argv;
char **envp;
{
extern void _exit();
char path[MAXPATHLEN];
char cmd[TOS_ARGS + 1];
size_t cmlen;
size_t enlen = 0;
size_t left, min_left;
char *p;
char *s, *t;
char *env;
long rval;
char *pconv, *pc, *tmp;
size_t len, cnt;
int i, done;
if (mode != P_WAIT && mode != P_OVERLAY && mode != P_NOWAIT) {
errno = EINVAL;
return -1;
}
(void)_unx2dos(_path, path); /* convert filename, if necessary */
if (!envp)
envp = environ;
/* try to find PCONVERT environment variable */
for (i = 0; (pconv = envp[i]) != 0; i++) {
if (! strncmp(pconv, "PCONVERT=", 9)) {
pconv += 9;
break;
}
}
/* count up space needed for environment */
for(cmlen = 0; argv[cmlen]; cmlen++)
enlen += strlen(argv[cmlen]) + 1;
enlen += 64; /* filler for stuff like ARGV= and zeros,
* minibuffer for empty param index conversion
*/
min_left = enlen;
for(cmlen = 0; envp[cmlen]; cmlen++)
enlen += strlen(envp[cmlen]) + 1;
enlen += 1024; /* buffer for _unx2dos */
try_again:
if ((env = (char *)Malloc((long)enlen)) == NULL) {
errno = ENOMEM;
return -1;
}
left = enlen;
s = env;
while ((p = *envp) != 0) {
/*
* NOTE: in main.c, we converted environment variables which contain paths into
* POSIX form. Here, we convert back into gulam form. Note that the
* new variable can be longer than the old, so space _is_ a problem.
*/
done = 0;
if (pconv) {
pc = pconv;
while (*pc) {
tmp = pc; len = 0;
while (*tmp && *tmp != ',') {
tmp++; len++;
}
if (! strncmp(p, pc, len) && p[len] == '=') {
len++;
tmp = p + len; /* tmp now after '=' */
cnt = 1;
while (*tmp) { /* count words */
if (*tmp == ':')
cnt++;
tmp++;
}
/* cnt * 2 is maximum enlargement when calling
* _path_unx2dos. Make this agree with _unx2dos
* in unx2dos.c
*/
if (left - (strlen(p) + cnt * 2 + 1) < min_left)
goto need_more_core;
strncpy(s, p, len);
_path_unx2dos(p + len, s + len);
while (*s) {
s++; left--;
}
s++; left--;
done = 1;
break;
}
if (! *tmp) break;
pc = tmp + 1;
}
}
else if (!strncmp(p, "PATH=", 5)) {
strncpy(s, p, 5); s += 5; p += 5; left -= 5;
tmp = p; /* tmp now after '=' */
cnt = 1;
while (*tmp) { /* count words */
if (*tmp == ':')
cnt++;
tmp++;
}
/* cnt * 2 is maximum enlargement when calling
* _path_unx2dos. Make this agree with _unx2dos
* in unx2dos.c
*/
if (left - (strlen(p) + cnt * 2 + 1) < min_left)
goto need_more_core;
_path_unx2dos(p, s);
while (*s) {
s++; left--;
}
s++; left--;
done = 1;
}
if (! done) {
/* copy variable without any conversion */
while (*p) {
*s++ = *p++;
if (--left <= min_left) {
need_more_core:
/* oh dear, we don't have enough core...
* so we Mfree what we already have, and try again with
* some more space.
*/
Mfree(env);
enlen += 1024;
goto try_again;
}
}
*s++ = 0;
left--;
}
envp++;
}
strcpy(s, "ARGV=");
s += 6; /* s+=sizeof("ARGV=") */
if (argv && *argv) {
unsigned long null_params = 0;
int digits, i;
unsigned long idx, val;
char **ap;
/* communicate empty arguments thru ARGV= value
*/
for (ap = argv, idx = 0;
*ap;
ap++, idx++)
{
if (! **ap) {
/* empty argument found
*/
if (! null_params) {
strcpy(s-1, "NULL:");
s += 4; /* s now points after "NULL:" */
left -= 6;
} else {
*s++ = ',' ;
}
null_params++;
/* convert index of zero param to ascii
*/
if (idx == 0) {
*s++ = '0';
digits = 1;
} else {
digits = 0;
val = idx;
while (val) {
for (i = digits; i > 0; i--)
s[i] = s[i - 1];
*s = "0123456789"[val % 10];
val /= 10;
digits++;
}
s += digits;
}
left -= digits + 2; /* 2 = sizeof( ',' in NULL:
* list + ' ' we put in place
* of empty params
*/
if (left < min_left)
goto need_more_core;
}
}
if (null_params) {
*s++ = 0; /* finish "NULL:" list */
}
/* copy argv[0] first (because it doesn't go into
* the command line)
*/
p = *argv;
if (! *p) { /* if empty argument */
*s++ = ' '; /* replace by space */
} else {
do {
*s++ = *p++;
} while (*p);
}
*s++ = '\0';
}
bzero(t = cmd, sizeof(cmd));
/* s points at the environment's copy of the args */
/* t points at the command line copy to be put in the basepage */
cmlen = 0;
if (argv && *argv) {
t++;
while (*++argv) {
p = *argv;
if (! *p) { /* if empty argument */
*s++ = ' '; /* replace by space */
/* write '' in TOS cmdlin
*/
if (cmlen < TOS_ARGS) {
*t++ = '\''; cmlen++;
}
if (cmlen < TOS_ARGS) {
*t++ = '\''; cmlen++;
}
} else {
do {
if (cmlen < TOS_ARGS) {
*t++ = *p; cmlen++;
}
*s++ = *p++;
} while (*p);
}
if (cmlen < TOS_ARGS && *(argv+1)) {
*t++ = ' '; cmlen++;
}
*s++ = '\0';
}
/* *cmd = (char) cmlen; NOT ANY MORE */
}
/* tie off environment */
*s++ = '\0';
*s = '\0';
/* signal Extended Argument Passing */
*cmd = 0x7f;
/* MiNT and MicroRTX support background processes with Pexec(100,...) */
/* MiNT supports overlays with Pexec(200,...) */
if (mode == P_NOWAIT) cmlen = 100;
else if (mode == P_OVERLAY && __mint) cmlen = 200;
else cmlen = 0;
rval = Pexec((int)cmlen, path, cmd, env);
if (rval < 0)
{
errno = (int) -rval;
rval = -1;
}
else if (mode == P_OVERLAY)
/* note that we get here only if MiNT is not active! */
_exit((int)rval);
(void)Mfree(env);
return (int) rval;
}