home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 099 / SH164AS.ZIP / LIB / POPEN.C < prev    next >
C/C++ Source or Header  |  1992-02-28  |  6KB  |  305 lines

  1. /*
  2.  * popen/pclose: simple MS-DOS piping scheme to imitate UNIX pipes
  3.  */
  4.  
  5. #include <sys/types.h>
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <errno.h>
  9. #include <process.h>
  10. #include <limits.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13.  
  14. typedef struct    pipes {
  15.     FILE    *p_fp;            /* File id            */
  16.     char    *p_process;        /* Program name            */
  17.     char    *p_file;        /* Pipe file name        */
  18.     int        p_status;        /* Status for close to return    */
  19.                     /* Read pipes only        */
  20.     char    p_write;        /* Read or write        */
  21. } PIPE;
  22.  
  23. static PIPE    P_list[_NFILE];        /* The pipe structures        */
  24. static int    Pipes_Inited = 0;    /* Initialised ?        */
  25. static int    Unique_Pipe  = 0;
  26.  
  27. static PIPE    *_p_save_entry (char *, char *);
  28. static int    _p_run (char *);
  29. static int    _p_reset_entry (PIPE *, int);
  30. static PIPE    *_p_get_entry (FILE *);
  31. static int    _p_onexit (void);
  32.  
  33. /* Set up a pipe structure */
  34.  
  35. static PIPE    *_p_save_entry (prog, mode)
  36. char        *prog;
  37. char        *mode;
  38. {
  39.     FILE    *fp;        /* File handler                */
  40.     PIPE    *pp;        /* Pipe handler structure        */
  41.     char    tmpfile[NAME_MAX + PATH_MAX + 2];
  42.     char    *tmpdir;    /* Points to directory prefix of pipe    */
  43.     char    s_mode = *mode;
  44.  
  45. /* Find out where we should put temporary files */
  46.  
  47.     if ((tmpdir = getenv ("TMPDIR")) == (char *) NULL) 
  48.     tmpdir = getenv ("TMP");
  49.  
  50. /* Use temporary directory if available */
  51.  
  52.     if (tmpdir == (char *)NULL) 
  53.     tmpdir = ".";
  54.  
  55. /* Get a unique pipe file name */
  56.  
  57.     sprintf (tmpfile, "%s/pipe%.4x.tmp", tmpdir, Unique_Pipe++);
  58.     unlink (tmpfile);
  59.  
  60. /* Create the pipe */
  61.  
  62.     *mode = 'w';
  63.     fp = fopen (tmpfile, mode);
  64.     *mode = s_mode;
  65.  
  66.     if (fp == (FILE *) NULL)
  67.     return (PIPE *)NULL;
  68.  
  69. /* Create the PIPE entry */
  70.  
  71.     if ((pp = _p_get_entry ((FILE *)NULL)) == (PIPE *)NULL)
  72.     {
  73.     fclose (fp);
  74.     unlink (tmpfile);
  75.     errno = EMFILE;
  76.     return (PIPE *)NULL;
  77.     }
  78.  
  79. /* Set up the entry */
  80.  
  81.     pp->p_fp      = fp;
  82.     pp->p_write   = *mode;
  83.     pp->p_process = strdup (prog);
  84.     pp->p_file    = strdup (tmpfile);
  85.  
  86. /* Check for errors */
  87.  
  88.     if ((pp->p_process == (char *)NULL) || (pp->p_file == (char *)NULL))
  89.     {
  90.     _p_reset_entry (pp, 1);
  91.     errno = ENOMEM;
  92.     return (FILE *)NULL;
  93.     }
  94.  
  95.     return pp;
  96. }
  97.  
  98. /* Execute command via SHELL or COMSPEC */
  99.  
  100. static int    _p_run (command)
  101. char        *command;
  102. {
  103.     char    *shell;            /* Command processor        */
  104.     char    *shellpath;        /* Full command processor path    */
  105.     char    *bp;            /* Generic string pointer    */
  106.     char    *dash = "/c";
  107.  
  108. /* Determine the command processor */
  109.  
  110.     if (((shell = getenv ("SHELL")) == (char *) NULL) &&
  111.     ((shell = getenv ("COMSPEC")) == (char *) NULL))
  112.     shell = "command.com";
  113.  
  114.     shellpath = strlwr (shell);
  115.  
  116. /* Strip off any leading backslash directories */
  117.  
  118.     if ((shell = strrchr (shellpath, '\\')) != (char *)NULL)
  119.     ++shell;
  120.  
  121.     else
  122.     shell = shellpath;
  123.  
  124. /* Strip off any leading slash directories */
  125.  
  126.     if ((bp = strrchr (shell, '/')) != (char *)NULL)
  127.     shell = ++bp;
  128.  
  129.     if (strcmp (shell, "command.com"))
  130.     *dash = '/';
  131.  
  132. /* Run the program */
  133.  
  134.     return spawnl (P_WAIT, shellpath, shell, dash, command, (char *) NULL);
  135. }
  136.  
  137. /* resetpipe: Private routine to cancel a pipe */
  138.  
  139. static int    _p_reset_entry (pp, mode)
  140. PIPE        *pp;
  141. int        mode;
  142. {
  143.     int        result = (!mode) ? 0 : -1;
  144.     int        serrno = errno;
  145.  
  146. /* Close the pipe */
  147.     
  148.     fclose (pp->p_fp);
  149.  
  150. /* Free up memory */
  151.  
  152.     if (pp->p_file != (char *)NULL)
  153.     {
  154.     result = unlink (pp->p_file);
  155.  
  156.     if (!mode)
  157.         serrno = errno;
  158.  
  159.     else
  160.         result = -1;
  161.  
  162.     free (pp->p_file);
  163.     }
  164.  
  165.     if (pp->p_process != (char *)NULL)
  166.     free (pp->p_process);
  167.  
  168.     memset (pp, 0, sizeof (PIPE));
  169.  
  170. /* Return error code */
  171.  
  172.     errno = serrno;
  173.     return result;
  174. }
  175.  
  176. /* Find a free entry */
  177.  
  178. static PIPE    *_p_get_entry (fp)
  179. FILE        *fp;
  180. {
  181.     int        i;
  182.  
  183.     for (i = 0; i < _NFILE; i++)
  184.     {
  185.     if (P_list[i].p_fp == fp)
  186.         return &P_list[i];
  187.     }
  188.     
  189.     return (PIPE *)NULL;
  190. }
  191.  
  192.  
  193. /* popen: open a pipe */
  194.  
  195. FILE    *popen (command, type)
  196. char    *command;        /* The command to be run        */
  197. char    *type;            /* "w" or "r"                */
  198.     int        old_stdout;
  199.     PIPE    *pp;
  200.  
  201. /* Initialise the pipe structure */
  202.  
  203.     if (!Pipes_Inited)
  204.     {
  205.     memset (&P_list[0], 0, sizeof (P_list));
  206.     Pipes_Inited = 1;
  207.  
  208.     if (onexit (_p_onexit) == (onexit_t)NULL)
  209.         return (FILE *)NULL;
  210.     }
  211.  
  212. /* For write style pipe, pclose handles program execution */
  213.  
  214.     if (*type == 'w')
  215.     return ((pp = _p_save_entry (command, type)) == (PIPE *)NULL)
  216.            ? (FILE *)NULL : pp->p_fp;
  217.     
  218. /* read pipe must create tmp file, set up stdout to point to the temp
  219.  * file, and run the program.  note that if the pipe file cannot be
  220.  * opened, it'll return a condition indicating pipe failure, which is
  221.  * fine.
  222.  */
  223.  
  224.     else if (*type == 'r')
  225.     {
  226.     if ((pp = _p_save_entry (command, type)) == (PIPE *)NULL)
  227.        return (FILE *)NULL;
  228.  
  229. /* Save the stdout file descriptor, dup the pipe onto standard out,
  230.  * execute the command, close the pipe and re-open it 
  231.  */
  232.  
  233.     if (((old_stdout = dup (fileno(stdout))) < 0)        ||
  234.         (dup2 (fileno (pp->p_fp), fileno(stdout)) < 0)    ||
  235.         ((pp->p_status = _p_run (command)) < 0)        ||
  236.         (fclose (pp->p_fp) < 0)                ||
  237.         (dup2 (old_stdout, fileno (stdout)) < 0)        ||
  238.         ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL))
  239.     {
  240.         _p_reset_entry (pp, 1);
  241.         return (FILE *)NULL;
  242.     }
  243.  
  244.     else
  245.         return pp->p_fp;
  246.     }
  247.     
  248. /* screwy call or unsupported type */
  249.  
  250.     errno = EINVAL;
  251.     return (FILE *)NULL;
  252. }
  253.  
  254. /* close a pipe */
  255.  
  256. int    pclose (fp)
  257. FILE    *fp;
  258. {
  259.     PIPE    *pp;            /* Current pipe structure    */
  260.     int        old_stdin;        /* Where our stdin points now    */
  261.  
  262.     if ((pp = _p_get_entry (fp)) == (PIPE *)NULL)
  263.     {
  264.     errno = EBADF;
  265.     return -1;
  266.     }
  267.  
  268.     if (fclose (pp->p_fp) < 0)
  269.     return _p_reset_entry (pp, 1);
  270.  
  271. /* Open the pipe in read mode, Save stdin file descriptor, copy pipe file
  272.  * descriptor to stdin, execute the command, and then restore stdin
  273.  */
  274.  
  275.     if ((pp->p_write == 'w') &&
  276.     (    ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL)    ||
  277.         ((old_stdin = dup (fileno (stdin))) < 0)        ||
  278.         (dup2 (fileno (pp->p_fp), fileno (stdin)) < 0)        ||
  279.         ((pp->p_status = _p_run (pp->p_process)) < 0)        ||
  280.         (fclose (pp->p_fp) < 0)                    ||
  281.         (dup2 (old_stdin, fileno (stdin)) < 0)
  282.     ))
  283.     return _p_reset_entry (pp, 1);
  284.  
  285. /* Close the temp file and remove it */
  286.  
  287.     return _p_reset_entry (pp, 0);
  288. }
  289.  
  290. /* Clean up on exit, in case a pipe has not been processed */
  291.  
  292. static int    _p_onexit ()
  293. {
  294.     int        i;
  295.  
  296.     for (i = 0; i < _NFILE; i++)
  297.     {
  298.     if (P_list[i].p_fp != (FILE *)NULL)
  299.         pclose (P_list[i].p_fp);
  300.     }
  301.  
  302.     return 0;
  303. }
  304.