home *** CD-ROM | disk | FTP | other *** search
/ Atari FTP / ATARI_FTP_0693.zip / ATARI_FTP_0693 / Mint / mntlib32.zoo / popen.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  3KB  |  120 lines

  1. /* popen(): open a file handle to a process. Works only under MiNT.
  2.  * Written by Eric R. Smith, based on the TOS version by Kai-Uwe Bloem.
  3.  */
  4.  
  5. #include    <stdio.h>
  6. #include    <stdlib.h>
  7. #include    <process.h>
  8. #include    <fcntl.h>
  9. #include    <string.h>
  10. #include    <errno.h>
  11. #include    <unistd.h>
  12.  
  13. __EXTERN int wait __PROTO((int *));
  14.  
  15. struct _pipe {
  16.     int    pid;        /* process id of child            */
  17.     FILE    *pfile;        /* created file descriptor        */
  18.     struct _pipe    *pnext;    /* next pipe in the list.        */
  19. };
  20.  
  21. static struct _pipe    *__pipes = NULL;    /* head of pipe list    */
  22.  
  23. FILE *popen(command, type)
  24. const char    *command, *type;
  25. {
  26.     struct _pipe *p;    /* the new pipe's list entry    */
  27.     int pipfd[2];        /* pipe file handles */
  28.     int savefd;        /* saved file descriptor for parent */
  29.     int kidfd;        /* file descriptor changed in child */
  30.                 /* 1 for "r", 0 for "w" */    
  31.  
  32.     char *shell;
  33.     FILE *pipefile = 0;
  34.     extern int __mint;
  35.  
  36.     if (__mint == 0) {
  37.         errno = EINVAL;
  38.         return (FILE *)0;
  39.     }
  40.  
  41.     shell = getenv("SHELL");
  42.     if (!shell)
  43.         shell = "sh";
  44.  
  45.     /* get space for the new pipe. If we can't get it then that's that */
  46.     p = (struct _pipe *) malloc(sizeof(struct _pipe));
  47.     if (p == NULL) return (FILE *)0;
  48.  
  49.     /* initialize the new pipe entry */
  50.     kidfd = (*type == 'r') ? 1 : 0;
  51.  
  52.     savefd = dup(kidfd);
  53.     /* get those close-on-exec flags right...
  54.        (well just do fork/exec would be easier :-)    -nox */
  55.  
  56.     if (savefd < 0 || fcntl (savefd, F_SETFD, (void *) 1) == -1 ||
  57.         pipe(pipfd) != 0) {            /* can't create pipe?? */
  58.         free(p);
  59.         return (FILE *)0;
  60.     }
  61.  
  62.     /* other side of the pipe should be closed in the child */
  63.     (void) fcntl(pipfd[1 - kidfd], F_SETFD, (void *) 1);
  64.     dup2(pipfd[kidfd], kidfd);
  65.     close(pipfd[kidfd]);
  66.     p->pid = spawnlp(P_NOWAIT, shell, shell, "-c", command, (char *)0);
  67.     dup2(savefd, kidfd);
  68.     close(savefd);
  69.  
  70.     if (p->pid > 0) {    /* command ran all right */
  71.     /* note: 1-kidfd tells us which handle to use in the parent */
  72.         pipefile = fdopen(pipfd[1 - kidfd], type);
  73.     }
  74.  
  75.     if (pipefile) {
  76.         p->pfile = pipefile;
  77.         p->pnext = __pipes;
  78.         __pipes = p;
  79.     }
  80.     else {
  81.         /* carefully release all resources */
  82.         close (pipfd[1 - kidfd]);
  83.         free(p);
  84.     }
  85.     return pipefile;
  86. }
  87.  
  88. /* close a pipe created by popen().
  89.  */
  90. int pclose(fp)
  91. FILE    *fp;
  92. {
  93.     struct _pipe    *p,        /* the pipe's list element    */
  94.             **q;        /* predecessor of p in the list    */
  95.     int    status = -1;        /* return status of the command    */
  96.     int    pid;
  97.  
  98.     /* search the pipe list for a pipe matching the FILE descriptor    */
  99.     for (p = __pipes, q = &__pipes;  p && p->pfile != fp;
  100.          q = &p->pnext, p = p->pnext);
  101.     if (p == NULL)        /* Never had a popen() for this file...    */
  102.         return status;    /* this pclose call makes no sense !    */
  103.  
  104.     fclose(p->pfile);    /* close the connection        */
  105.  
  106. /* now wait for the command to finish */
  107.  
  108.     do {
  109.         pid = wait(&status);
  110.     } while (pid >= 0 && pid != p->pid);
  111.  
  112.     /* remove the pipe from the list */
  113.     *q = p->pnext;
  114.  
  115.     /* Now free the pipe entry */
  116.     free(p);
  117.  
  118.     return status;
  119. }
  120.