home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib32.zoo / spawn.c < prev    next >
C/C++ Source or Header  |  1993-05-25  |  7KB  |  335 lines

  1. /*
  2.    89/03/02: ERS: added the "mode" argument for MS-DOS/Unix
  3.    compatibility. Added prototypes for GNU C.
  4.  
  5.    fixed spawnve: the original didn't pass the command tail
  6.    correctly, nor did it handle errno right. Also, this version
  7.    passes args in the environment as well as the command line,
  8.    using the ARGV= mechanism supported by crt0.s
  9.  
  10.    Written 89/01/10 by ERS. Original version Copyright (c) 1988 by
  11.    Memorial University of Newfoundland. This version is based upon
  12.    that original, but is substantially different. (In fact, there
  13.    probably isn't a single line of the original left.)
  14.  
  15.    Adapted 90/06/25 by ERS to MiNT.
  16.  
  17.    08 Apr 93 hohmuth
  18.     added support for ARGV standard extension allowing empty arguments
  19.  
  20.    uo, 3.5.93, throw away some static characterarrays (path[] and
  21.    cmd[]).
  22.  
  23. */
  24.  
  25. #include    <stdarg.h>
  26. #include    <process.h>
  27. #include    <param.h>
  28. #include    <errno.h>
  29. #include    <osbind.h>
  30. #include    <mintbind.h>
  31. #include    <stdlib.h>
  32. #include    <time.h>
  33. #include    <string.h>
  34. #include    <unistd.h>
  35. #include    "lib.h"
  36.  
  37. #define TOS_ARGS 126
  38.  
  39. extern char **environ;
  40. extern int __mint;
  41.  
  42.  
  43. int
  44. _spawnve(mode, _path, argv, envp)
  45.     int    mode;
  46.     char    *_path;
  47.     char    **argv;
  48.     char    **envp;
  49. {
  50.     extern void _exit();
  51.     char        path[MAXPATHLEN];
  52.     char        cmd[TOS_ARGS + 1];
  53.     size_t        cmlen;
  54.     size_t        enlen = 0;
  55.     size_t        left, min_left;
  56.     char        *p;
  57.     char        *s, *t;
  58.     char        *env;
  59.     long        rval;
  60.     char *pconv, *pc, *tmp;
  61.     size_t len, cnt;
  62.     int i, done;
  63.  
  64.     if (mode != P_WAIT && mode != P_OVERLAY && mode != P_NOWAIT) {
  65.         errno = EINVAL;
  66.         return -1;
  67.     }
  68.     (void)_unx2dos(_path, path);    /* convert filename, if necessary */
  69.     if (!envp)
  70.         envp = environ;
  71.  
  72. /* try to find PCONVERT environment variable */
  73.     for (i = 0; (pconv = envp[i]) != 0; i++) {
  74.         if (! strncmp(pconv, "PCONVERT=", 9)) {
  75.             pconv += 9;
  76.             break;
  77.         }
  78.     }
  79.  
  80. /* count up space needed for environment */
  81.     for(cmlen = 0; argv[cmlen]; cmlen++)
  82.         enlen += strlen(argv[cmlen]) + 1;
  83.     enlen += 64;    /* filler for stuff like ARGV= and zeros, 
  84.              * minibuffer for empty param index conversion 
  85.              */
  86.     min_left = enlen;
  87.     for(cmlen = 0; envp[cmlen]; cmlen++)
  88.         enlen += strlen(envp[cmlen]) + 1;
  89.     enlen += 1024;    /* buffer for _unx2dos */
  90.  
  91. try_again:
  92.     if ((env = (char *)Malloc((long)enlen)) == NULL) {
  93.         errno = ENOMEM;
  94.         return -1;
  95.     }
  96.     left = enlen;
  97.     s = env;
  98.  
  99.     while ((p = *envp) != 0) {
  100. /*
  101.  * NOTE: in main.c, we converted environment variables which contain paths into
  102.  * POSIX form. Here, we convert back into gulam form. Note that the
  103.  * new variable can be longer than the old, so space _is_ a problem.
  104.  */
  105.         done = 0;
  106.         
  107.         if (pconv) {
  108.  
  109.             pc = pconv;
  110.             while (*pc) {
  111.                 
  112.                 tmp = pc; len = 0;
  113.                 while (*tmp && *tmp != ',') {
  114.                     tmp++; len++;
  115.                 }
  116.                 
  117.                 if (! strncmp(p, pc, len) && p[len] == '=') {
  118.                     len++;
  119.                     tmp = p + len;        /* tmp now after '=' */    
  120.                     cnt = 1;
  121.                     while (*tmp) {        /* count words */
  122.                         if (*tmp == ':')
  123.                             cnt++;
  124.                         tmp++;
  125.                     }
  126.  
  127.                     /* cnt * 2 is maximum enlargement when calling
  128.                      * _path_unx2dos. Make this agree with _unx2dos
  129.                      * in unx2dos.c
  130.                      */
  131.                     if (left - (strlen(p) + cnt * 2 + 1) < min_left)
  132.                         goto need_more_core;
  133.                         
  134.                     strncpy(s, p, len);
  135.                     _path_unx2dos(p + len, s + len);
  136.  
  137.                     while (*s) {
  138.                         s++; left--;
  139.                     }
  140.                     s++; left--;
  141.                     
  142.                     done = 1;
  143.                     break;    
  144.                 }
  145.                 
  146.                 if (! *tmp) break;
  147.                 pc = tmp + 1;
  148.             }
  149.         }
  150.         else if (!strncmp(p, "PATH=", 5)) {
  151.             strncpy(s, p, 5); s += 5; p += 5; left -= 5;
  152.  
  153.             tmp = p;        /* tmp now after '=' */    
  154.             cnt = 1;
  155.             while (*tmp) {        /* count words */
  156.                 if (*tmp == ':')
  157.                     cnt++;
  158.                 tmp++;
  159.             }
  160.  
  161.             /* cnt * 2 is maximum enlargement when calling
  162.              * _path_unx2dos. Make this agree with _unx2dos
  163.              * in unx2dos.c
  164.              */
  165.             if (left - (strlen(p) + cnt * 2 + 1) < min_left)
  166.                 goto need_more_core;
  167.                         
  168.             _path_unx2dos(p, s);
  169.  
  170.             while (*s) {
  171.                 s++; left--;
  172.             }
  173.             s++; left--;
  174.         
  175.             done = 1;
  176.         }            
  177.         
  178.         if (! done) {
  179.             /* copy variable without any conversion */
  180.             while (*p) {
  181.                 *s++ = *p++;
  182.                 if (--left <= min_left) {
  183. need_more_core:
  184.                     /* oh dear, we don't have enough core...
  185.                      * so we Mfree what we already have, and try again with
  186.                      * some more space.
  187.                      */
  188.                     Mfree(env);
  189.                     enlen += 1024;
  190.                     goto try_again;
  191.                 }
  192.             }
  193.             *s++ = 0;
  194.             left--;
  195.         }
  196.  
  197.         envp++;
  198.     }
  199.     
  200.     strcpy(s, "ARGV=");
  201.     s += 6; /* s+=sizeof("ARGV=") */
  202.  
  203.     if (argv && *argv) {
  204.         unsigned long null_params = 0;
  205.         int digits, i;
  206.         unsigned long idx, val;
  207.         char **ap;
  208.         
  209.         /* communicate empty arguments thru ARGV= value
  210.          */
  211.         for (ap = argv, idx = 0; 
  212.              *ap;
  213.              ap++, idx++)
  214.         {
  215.             if (! **ap) {
  216.                 /* empty argument found
  217.                  */
  218.                 if (! null_params) {
  219.                     strcpy(s-1, "NULL:");
  220.                     s += 4;    /* s now points after "NULL:" */
  221.                     left -= 6;
  222.                 } else {
  223.                     *s++ = ',' ;
  224.                 }
  225.                 null_params++;
  226.                                     
  227.                 /* convert index of zero param to ascii
  228.                  */
  229.                 if (idx == 0) {
  230.                     *s++ = '0';
  231.                     digits = 1;
  232.                 } else {
  233.                     digits = 0;
  234.                     val = idx;
  235.                     while (val) {
  236.                         for (i = digits; i > 0; i--)
  237.                             s[i] = s[i - 1];
  238.                         *s = "0123456789"[val % 10];
  239.                         val /= 10;
  240.                         digits++;
  241.                     }
  242.                     s += digits;
  243.                 }
  244.                 
  245.                 left -= digits + 2; /* 2 = sizeof( ',' in NULL:
  246.                              * list + ' ' we put in place
  247.                              * of empty params
  248.                              */
  249.                 if (left < min_left)
  250.                     goto need_more_core;
  251.             }
  252.         }
  253.  
  254.         if (null_params) {
  255.             *s++ = 0;        /* finish "NULL:" list */
  256.         }
  257.  
  258.         /* copy argv[0] first (because it doesn't go into 
  259.          * the command line)
  260.          */
  261.         p = *argv;
  262.         if (! *p) {        /* if empty argument */
  263.             *s++ = ' ';    /* replace by space */
  264.         } else {
  265.              do {
  266.             *s++ = *p++;
  267.              } while (*p);
  268.         }
  269.         *s++ = '\0';
  270.     }
  271.  
  272.     bzero(t = cmd, sizeof(cmd));
  273.  
  274. /* s points at the environment's copy of the args */
  275. /* t points at the command line copy to be put in the basepage */
  276.  
  277.         cmlen = 0;
  278.     if (argv && *argv) {
  279.         t++;
  280.         while (*++argv) {
  281.             p = *argv;
  282.             if (! *p) {    /* if empty argument */
  283.                  *s++ = ' ';    /* replace by space */
  284.                        /* write '' in TOS cmdlin
  285.                         */
  286.                  if (cmlen < TOS_ARGS) {
  287.                      *t++ = '\''; cmlen++;
  288.                  }
  289.                  if (cmlen < TOS_ARGS) {
  290.                      *t++ = '\''; cmlen++;
  291.                  }
  292.             } else {
  293.                  do {
  294.                               if (cmlen < TOS_ARGS) {
  295.                                       *t++ = *p; cmlen++;
  296.                               }
  297.                 *s++ = *p++;
  298.                  } while (*p);
  299.             }
  300.                         if (cmlen < TOS_ARGS && *(argv+1)) {
  301.                                 *t++ = ' '; cmlen++;
  302.                         }
  303.             *s++ = '\0';
  304.         }
  305. /*                *cmd = (char) cmlen;  NOT ANY MORE */
  306.     }
  307.  
  308.     /* tie off environment */
  309.     *s++ = '\0';
  310.     *s = '\0';
  311.  
  312.     /* signal Extended Argument Passing */
  313.     *cmd = 0x7f;
  314.  
  315. /* MiNT and MicroRTX support background processes with Pexec(100,...) */
  316. /* MiNT supports overlays with Pexec(200,...) */
  317.  
  318.     if (mode == P_NOWAIT) cmlen = 100;
  319.     else if (mode == P_OVERLAY && __mint) cmlen = 200;
  320.     else cmlen = 0;
  321.  
  322.     rval = Pexec((int)cmlen, path, cmd, env);
  323.  
  324.     if (rval < 0)
  325.     {
  326.         errno = (int) -rval;
  327.         rval = -1;
  328.     }
  329.     else if (mode == P_OVERLAY)
  330.     /* note that we get here only if MiNT is not active! */
  331.         _exit((int)rval);
  332.     (void)Mfree(env);
  333.     return (int) rval;
  334. }
  335.