305 lines
6.8 KiB
C
305 lines
6.8 KiB
C
/*_ system.c Sun Apr 16 1989 Modified by: Walter Bright */
|
||
/* OS2 support added by Nikki Locke May 1989 */
|
||
/* Copyright (C) 1985-1989 by Northwest Software */
|
||
/* All Rights Reserved */
|
||
/* Written by Walter Bright */
|
||
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <process.h>
|
||
#include <dos.h>
|
||
|
||
/* From exec2.asm */
|
||
#ifdef __OS2__
|
||
extern int _exec(char *command,char *commandline,char *envptr,int chain);
|
||
#else
|
||
extern int _exec(char *command,char *commandline,int envseg,int chain);
|
||
#endif
|
||
|
||
static int near pascal _forkv(int mode,char *path,char **argv,int chain);
|
||
static int near pascal _forkvp(int mode,char *cmd,char **argv,int flag);
|
||
|
||
#ifndef __OS2__
|
||
static void near pascal flushrelease(void);
|
||
#endif
|
||
|
||
/**************************
|
||
* Execute command line using COMMAND.COM.
|
||
* Note that since COMMAND.COM doesn't return the exit status of the
|
||
* program it ran, we can't either. All we can return is the exit
|
||
* status of COMMAND.COM itself.
|
||
* Returns:
|
||
* 0 success
|
||
* -1 error
|
||
*/
|
||
|
||
int system(const char *cmdline)
|
||
{ char *comspec;
|
||
|
||
comspec = getenv("COMSPEC");
|
||
return spawnl(0,comspec,"COMMAND.COM","/c",cmdline,(char *) NULL);
|
||
}
|
||
|
||
/*************************
|
||
* Here are all the spawn commands.
|
||
* The 'p' functions bip along the PATH environment variable looking
|
||
* for the command.
|
||
* Input:
|
||
* mode ignored
|
||
* path the command name
|
||
* (if no ., .COM is tried first, then .EXE)
|
||
* arg0 also the command name (but ignored)
|
||
* argn... list of pointers to args terminated with a NULL
|
||
* Returns:
|
||
* -1 error (errno is set)
|
||
* n exit status from spawned process
|
||
*/
|
||
|
||
int spawnl(int mode,char *path,char *arglist,...)
|
||
{
|
||
return spawnv(mode,path,&arglist);
|
||
}
|
||
|
||
int spawnv(int mode,char *path,char **argv)
|
||
{
|
||
return _forkv(mode,path,argv,0);
|
||
}
|
||
|
||
int spawnlp(int mode,char *path,char *arglist,...)
|
||
{
|
||
return spawnvp(mode,path,&arglist);
|
||
}
|
||
|
||
int spawnvp(int mode,char *cmd,char **argv)
|
||
{
|
||
return _forkvp(mode,cmd,argv,0);
|
||
}
|
||
|
||
static int near pascal _forkv(int mode,char *path,char **argv,int chain)
|
||
{ char argbuf[1 + 128 + 1],*a;
|
||
/* D: path name . ext 0 */
|
||
char cmdbuf[2 + 64 + 8 + 1 + 3 + 1];
|
||
int i,status;
|
||
|
||
/* Build argbuf[] */
|
||
i = 0;
|
||
#ifdef __OS2__
|
||
a = &argbuf[0];
|
||
if(*argv)
|
||
{
|
||
i = strlen(*argv);
|
||
if (i > 128 - 1) /* leave room for \0 at end */
|
||
goto err;
|
||
strcpy(a,*argv++);
|
||
a += strlen(a) + 1; /* move past argument */
|
||
}
|
||
#else
|
||
a = &argbuf[1];
|
||
if (*argv)
|
||
argv++; /* skip over arg0 */
|
||
#endif
|
||
*a = 0;
|
||
while (*argv)
|
||
{
|
||
i += strlen(*argv);
|
||
if (i > 128 - 1) /* leave room for \r at end */
|
||
{
|
||
err: errno = E2BIG;
|
||
return -1;
|
||
}
|
||
strcat(a,*argv++);
|
||
if (*argv) /* if more arguments */
|
||
{ i++;
|
||
if (i > 128 - 1)
|
||
goto err;
|
||
strcat(a," "); /* separate with a space */
|
||
}
|
||
}
|
||
#ifndef __OS2__
|
||
argbuf[0] = i; /* # of bytes in command line */
|
||
if (argbuf[i] != '\r') /* if not already ending in \r */
|
||
strcat(a,"\r"); /* terminate command with \r */
|
||
#endif
|
||
|
||
if (!path)
|
||
goto badpath;
|
||
i = strlen(path);
|
||
a = path + i;
|
||
while (1)
|
||
{ switch (*a)
|
||
{
|
||
default:
|
||
if (a == path)
|
||
goto L1;
|
||
a--;
|
||
continue;
|
||
case '.': /* if already a . or extension */
|
||
if (i > sizeof(cmdbuf) - 1)
|
||
goto badpath;
|
||
strcpy(cmdbuf,path);
|
||
break;
|
||
case '\\':
|
||
case ':':
|
||
case '/': /* no . or extension for command */
|
||
L1:
|
||
if (i > sizeof(cmdbuf) - 1 - 4)
|
||
goto badpath;
|
||
strcpy(cmdbuf,path);
|
||
strcat(cmdbuf,".COM"); /* try .COM extension */
|
||
/*printf("cmdbuf = '%s', argbuf = '%s'\n",cmdbuf,argbuf + 1);*/
|
||
if (filesize(cmdbuf) != -1)
|
||
{
|
||
#ifdef __OS2__
|
||
return _exec(cmdbuf,argbuf,0,mode);
|
||
#else
|
||
if (chain)
|
||
flushrelease();
|
||
return _exec(cmdbuf,argbuf,0,chain);
|
||
#endif
|
||
}
|
||
errno = 0;
|
||
strcpy(&cmdbuf[i],".EXE"); /* try .EXE extension */
|
||
break;
|
||
}
|
||
break;
|
||
}
|
||
/*printf("cmdbuf = '%s', argbuf = '%s'\n",cmdbuf,argbuf + 1);*/
|
||
if (filesize(cmdbuf) == -1)
|
||
{ errno = 2; /* file not found or path invalid */
|
||
status = -1;
|
||
}
|
||
else
|
||
{
|
||
#ifdef __OS2__
|
||
status = _exec(cmdbuf,argbuf,0,mode);
|
||
#else
|
||
if (chain)
|
||
flushrelease();
|
||
status = _exec(cmdbuf,argbuf,0,chain);
|
||
#endif
|
||
}
|
||
return status;
|
||
|
||
badpath:
|
||
errno = ENOENT;
|
||
return -1;
|
||
}
|
||
|
||
static int near pascal _forkvp(int mode,char *cmd,char **argv,int flag)
|
||
{ char *p;
|
||
int status;
|
||
/* D: path name . ext 0 */
|
||
char cmdbuf[2 + 64 + 8 + 1 + 3 + 1 + 1],*pc;
|
||
/* The one extra at the end is in case we add a \ to the end */
|
||
/* of the path. Hopefully, this will still cause an error in */
|
||
/* spawnv(). */
|
||
|
||
status = _forkv(mode,cmd,argv,flag);
|
||
if (status >= 0 || errno != ENOENT)
|
||
return status;
|
||
|
||
p = getenv("PATH");
|
||
if (!p || strlen(cmd) > 8 + 1 + 3) /* if no path or cmd too long */
|
||
return status;
|
||
while (*p)
|
||
{
|
||
pc = cmdbuf;
|
||
while (*p)
|
||
{ if (*p == ';') /* path separator */
|
||
{ p++;
|
||
break;
|
||
}
|
||
if (pc < &cmdbuf[2 + 64])
|
||
*pc++ = *p;
|
||
p++;
|
||
}
|
||
if (pc > cmdbuf && *(pc - 1) != '\\')
|
||
*pc++ = '\\';
|
||
*pc = 0;
|
||
strcat(cmdbuf,cmd); /* guaranteed not to overflow */
|
||
status = _forkv(mode,cmdbuf,argv,flag);
|
||
if (status >= 0 || errno != ENOENT)
|
||
break;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
/********************************
|
||
* exec() functions work just like the spawn() ones do, except that
|
||
* the command is not returned from unless there is an error.
|
||
* The DOS implementation is flawed:
|
||
* o If there is insufficient memory to run the program,
|
||
* or if the .EXE file is invalid, the parent will simply
|
||
* terminate with an errorlevel of 1.
|
||
* o About 768 bytes is lost for each exec, so circular
|
||
* execs will eventually run out of memory.
|
||
*/
|
||
|
||
int execl(char *path,char *arglist,...)
|
||
{
|
||
return execv(path,&arglist);
|
||
}
|
||
|
||
int execv(char *path,char **argv)
|
||
{
|
||
#ifdef __OS2__
|
||
int status;
|
||
|
||
status = _forkv(1,path,argv,1);
|
||
if(status == -1)
|
||
perror("Exec format error");
|
||
exit(0);
|
||
#else
|
||
return _forkv(0,path,argv,1);
|
||
#endif
|
||
}
|
||
|
||
int execlp(char *path,char *arglist,...)
|
||
{
|
||
return execvp(path,&arglist);
|
||
}
|
||
|
||
int execvp(char *cmd,char **argv)
|
||
{
|
||
#ifdef __OS2__
|
||
int status;
|
||
|
||
status = _forkvp(1,cmd,argv,1);
|
||
if(status == -1)
|
||
perror("Exec format error");
|
||
exit(0);
|
||
#else
|
||
return _forkvp(0,cmd,argv,1);
|
||
#endif
|
||
}
|
||
|
||
#ifndef __OS2__
|
||
/**************************
|
||
* Flush output, and release memory for buffers outside the data segment.
|
||
*/
|
||
|
||
static void near pascal flushrelease(void)
|
||
{ FILE *fp;
|
||
int flag;
|
||
|
||
for (fp = &_iob[0]; fp < &_iob[_NFILE]; fp++)
|
||
{
|
||
flag = fp->_flag;
|
||
if (flag & (_IOREAD | _IOWRT | _IORW))
|
||
{ /* flush buffer */
|
||
if (!(flag & _IONBF))
|
||
{ fflush(fp);
|
||
#ifdef BIGBUF
|
||
/* dump big buffer if there is one */
|
||
if (flag & _IOBIGBUF && fp->_seg)
|
||
dos_free(fp->_seg);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|