home *** CD-ROM | disk | FTP | other *** search
- /*
- * system(): execute a command, passed as a string
- *
- * Written by Eric R. Smith and placed in the public domain.
- *
- * Modified by Allan Pratt to call _unx2dos on redirect file names
- * and to call spawnvp() without calling fork() -- why bother?
- *
- */
-
- #include <limits.h>
- #include <string.h>
- #include <ctype.h>
- #include <stdlib.h>
- #include <process.h>
- #include <errno.h>
- #include <file.h>
- #include <osbind.h>
- #include <unistd.h>
- #include "lib.h"
-
- #define isquote(c) ((c) == '\"' || (c) == '\'' || (c) == '`')
- #define ARG_ERR ( (Argentry *) -1 )
-
- /* struct. used to build a list of arguments for the command */
-
- typedef struct argentry {
- struct argentry *next;
- char string[1];
- } Argentry;
-
-
- /* allocate an Argentry that will hold the string "s" */
-
- static Argentry *_argalloc(s)
- const char *s;
- {
- Argentry *x;
-
- x = (Argentry *) malloc((size_t)(sizeof(Argentry) + strlen(s) + 1));
- if (!x)
- return ARG_ERR;
- x->next = (Argentry *) 0;
- strcpy(x->string, s);
- return x;
- }
-
- /* free a list of Argentries */
-
- static void _argfree(p)
- Argentry *p;
- {
- Argentry *oldp;
-
- while (p) {
- oldp = p;
- p = p->next;
- free(oldp);
- }
- }
-
- /* parse a string into a list of Argentries. Words are defined to be
- * (1) any sequence of non-blank characters
- * (2) any sequence of characters starting with a ', ", or ` and ending
- * with the same character. These quotes are stripped off.
- * (3) any spaces after an unquoted > or < are skipped, so
- * "ls > junk" is parsed as 'ls' '>junk'.
- */
-
- static Argentry *_parseargs(s)
- const char *s;
- {
- Argentry *cur, *res;
- char buf[PATH_MAX];
- char *t, quote;
-
- res = cur = _argalloc("");
-
- for(;;) {
- t = buf;
- again:
- while (isspace(*s)) s++;
- if (!*s) break;
- if (isquote(*s)) {
- quote = *s++;
- while (*s && *s != quote)
- *t++ = *s++;
- if (*s) s++; /* skip final quote */
- }
- else {
- while (*s && !isspace(*s))
- *t++ = *s++;
- if (*s && ( *(s-1) == '>' || *(s-1) == '<' ))
- goto again;
- }
- *t = 0;
- cur->next = _argalloc(buf);
- if (!(cur = cur->next)) /* couldn't alloc() */
- return ARG_ERR;
- }
- cur->next = (Argentry *) 0;
- cur = res; res = res->next; free(cur);
- return res;
- }
-
-
- /* Here is system() itself.
- * FIXME: we probably should do wildcard expansion.
- * also, should errno get set here??
- */
-
- int system(s)
- const char *s;
- {
- Argentry *al, *cur;
- char **argv, *p;
- int argc, i;
- char *infile, *outfile;
- int infd = 0, outfd = 1, append = 0;
- int oldin = 0, oldout = 1; /* hold the Fdup'd in, out */
- char path[PATH_MAX];
- int retval;
-
- if (!s) /* check for system() supported ?? */
- return 1;
- al = _parseargs(s); /* get a list of args */
- if (al == ARG_ERR) { /* not enough memory */
- return errno = ENOMEM;
- return -1;
- }
-
- infile = outfile = "";
-
- /* convert the list returned by _parseargs to the normal char *argv[] */
- argc = i = 0;
- for (cur = al; cur; cur = cur->next)
- argc++;
- if (!(argv = (char **) malloc((size_t)(argc * sizeof(char *))))) {
- errno = ENOMEM; return -1;
- }
- for (cur = al; cur; cur = cur->next) {
- p = cur->string;
- if (*p == '>') {
- outfile = p+1;
- if (*outfile == '>') {
- outfile++;
- append = 1;
- }
- else
- append = 0;
- }
- else if (*p == '<') {
- infile = p+1;
- }
- else
- argv[i++] = p;
- }
- argv[i] = (char *)0;
-
- /* now actually run the program */
-
- if (*infile) {
- (void)_unx2dos(infile,path);
- infd = Fopen(path, 0);
- if (infd < __SMALLEST_VALID_HANDLE) {
- perror(infile);
- _exit(2);
- }
- oldin = Fdup(0);
- (void)Fforce(0, infd);
- }
- if (*outfile) {
- (void)_unx2dos(outfile,path);
- if (append) {
- outfd = Fopen(path, 2);
- if (outfd < __SMALLEST_VALID_HANDLE)
- outfd = Fcreate(path, 0);
- else
- (void)Fseek(0L, outfd, 2);
- }
- else
- outfd = Fcreate(path, 0);
- if (outfd < __SMALLEST_VALID_HANDLE) {
- perror(outfile);
- _exit(2);
- }
- oldout = Fdup(1);
- (void)Fforce(1, outfd);
- }
-
- retval = spawnvp(P_WAIT, argv[0], argv);
-
- if (*infile) (void)(Fforce(0,oldin), Fclose(oldin), Fclose(infd));
- if (*outfile) (void)(Fforce(1,oldout), Fclose(oldout), Fclose(outfd));
- free(argv);
- _argfree(al);
- return retval;
- }
-