home *** CD-ROM | disk | FTP | other *** search
/ GEMini Atari / GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso / zip / gnu / mntlib16.lzh / MNTLIB16 / SYSTEM.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  4KB  |  199 lines

  1. /*
  2.  * system(): execute a command, passed as a string
  3.  *
  4.  * Written by Eric R. Smith and placed in the public domain.
  5.  *
  6.  * Modified by Allan Pratt to call _unx2dos on redirect file names
  7.  * and to call spawnvp() without calling fork() -- why bother?
  8.  *
  9.  */
  10.  
  11. #include <limits.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <stdlib.h>
  15. #include <process.h>
  16. #include <errno.h>
  17. #include <file.h>
  18. #include <osbind.h>
  19. #include <unistd.h>
  20. #include "lib.h"
  21.  
  22. #define isquote(c) ((c) == '\"' || (c) == '\'' || (c) == '`')
  23. #define ARG_ERR       ( (Argentry *) -1 )
  24.  
  25. /* struct. used to build a list of arguments for the command */
  26.  
  27. typedef struct argentry {
  28.     struct argentry *next;
  29.     char    string[1];
  30. } Argentry;
  31.  
  32.  
  33. /* allocate an Argentry that will hold the string "s" */
  34.  
  35. static Argentry *_argalloc(s)
  36.     const char *s;
  37. {
  38.     Argentry *x;
  39.  
  40.     x = (Argentry *) malloc((size_t)(sizeof(Argentry) + strlen(s) + 1));
  41.     if (!x)
  42.         return ARG_ERR;
  43.     x->next = (Argentry *) 0;
  44.     strcpy(x->string, s);
  45.     return x;
  46. }
  47.  
  48. /* free a list of Argentries */
  49.  
  50. static void _argfree(p)
  51.     Argentry *p;
  52. {
  53.     Argentry *oldp;
  54.  
  55.     while (p) {
  56.         oldp = p;
  57.         p = p->next;
  58.         free(oldp);
  59.     }
  60. }
  61.  
  62. /* parse a string into a list of Argentries. Words are defined to be
  63.  * (1) any sequence of non-blank characters
  64.  * (2) any sequence of characters starting with a ', ", or ` and ending
  65.  *     with the same character. These quotes are stripped off.
  66.  * (3) any spaces after an unquoted > or < are skipped, so
  67.  *     "ls > junk" is parsed as 'ls' '>junk'.
  68.  */
  69.  
  70. static Argentry *_parseargs(s)
  71.     const char *s;
  72. {
  73.     Argentry *cur, *res;
  74.     char buf[PATH_MAX];
  75.     char *t, quote;
  76.  
  77.     res = cur = _argalloc("");
  78.  
  79.     for(;;) {
  80.         t = buf;
  81. again:
  82.         while (isspace(*s)) s++;
  83.         if (!*s) break;
  84.         if (isquote(*s)) {
  85.             quote = *s++;
  86.             while (*s && *s != quote)
  87.                 *t++ = *s++;
  88.             if (*s) s++;    /* skip final quote */
  89.         }
  90.         else {
  91.             while (*s && !isspace(*s))
  92.                 *t++ = *s++;
  93.             if (*s && ( *(s-1) == '>' || *(s-1) == '<' ))
  94.                 goto again;
  95.         }
  96.         *t = 0;
  97.         cur->next = _argalloc(buf);
  98.         if (!(cur = cur->next))      /* couldn't alloc() */
  99.             return ARG_ERR;
  100.     }
  101.     cur->next = (Argentry *) 0;
  102.     cur = res; res = res->next; free(cur);
  103.     return res;
  104. }
  105.  
  106.  
  107. /* Here is system() itself.
  108.  * FIXME: we probably should do wildcard expansion.
  109.  * also, should errno get set here??
  110.  */
  111.  
  112. int system(s)
  113.     const char *s;
  114. {
  115.     Argentry *al, *cur;
  116.     char **argv, *p;
  117.     int  argc, i;
  118.     char *infile, *outfile;
  119.     int  infd = 0, outfd = 1, append = 0;
  120.     int oldin = 0, oldout = 1;    /* hold the Fdup'd in, out */
  121.     char path[PATH_MAX];
  122.     int retval;
  123.  
  124.     if (!s)        /* check for system() supported ?? */
  125.         return 1;
  126.     al = _parseargs(s);        /* get a list of args */
  127.     if (al == ARG_ERR) {        /* not enough memory */
  128.         return errno = ENOMEM;
  129.         return -1;
  130.     }
  131.  
  132.     infile = outfile = "";
  133.  
  134. /* convert the list returned by _parseargs to the normal char *argv[] */
  135.     argc = i = 0;
  136.     for (cur = al; cur; cur = cur->next)
  137.         argc++;
  138.     if (!(argv = (char **) malloc((size_t)(argc * sizeof(char *))))) {
  139.         errno = ENOMEM; return -1;
  140.     }
  141.     for (cur = al; cur; cur = cur->next) {
  142.         p = cur->string;
  143.         if (*p == '>') {
  144.             outfile = p+1;
  145.             if (*outfile == '>') {
  146.                 outfile++;
  147.                 append = 1;
  148.             }
  149.             else
  150.             append = 0;
  151.         }
  152.         else if (*p == '<') {
  153.             infile = p+1;
  154.         }
  155.         else
  156.             argv[i++] = p;
  157.     }
  158.      argv[i] = (char *)0;
  159.  
  160. /* now actually run the program */
  161.  
  162.     if (*infile) {
  163.         (void)_unx2dos(infile,path);
  164.         infd = Fopen(path, 0);
  165.         if (infd < __SMALLEST_VALID_HANDLE) {
  166.             perror(infile);
  167.             _exit(2);
  168.         }
  169.         oldin = Fdup(0);
  170.         (void)Fforce(0, infd);
  171.     }
  172.     if (*outfile) {
  173.         (void)_unx2dos(outfile,path);
  174.         if (append) {
  175.             outfd = Fopen(path, 2);
  176.             if (outfd < __SMALLEST_VALID_HANDLE)
  177.                 outfd = Fcreate(path, 0);
  178.             else
  179.                 (void)Fseek(0L, outfd, 2);
  180.         }
  181.         else
  182.             outfd = Fcreate(path, 0);
  183.         if (outfd < __SMALLEST_VALID_HANDLE) {
  184.             perror(outfile);
  185.             _exit(2);
  186.         }
  187.         oldout = Fdup(1);
  188.         (void)Fforce(1, outfd);
  189.     }
  190.  
  191.     retval = spawnvp(P_WAIT, argv[0], argv);
  192.  
  193.     if (*infile) (void)(Fforce(0,oldin), Fclose(oldin), Fclose(infd));
  194.     if (*outfile) (void)(Fforce(1,oldout), Fclose(oldout), Fclose(outfd));
  195.     free(argv);
  196.     _argfree(al);
  197.     return retval;
  198. }
  199.