home *** CD-ROM | disk | FTP | other *** search
- /*
- * popen/pclose: simple MS-DOS piping scheme to imitate UNIX pipes
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <process.h>
- #include <limits.h>
- #include <stdlib.h>
- #include <unistd.h>
-
- typedef struct pipes {
- FILE *p_fp; /* File id */
- char *p_process; /* Program name */
- char *p_file; /* Pipe file name */
- int p_status; /* Status for close to return */
- /* Read pipes only */
- char p_write; /* Read or write */
- } PIPE;
-
- static PIPE P_list[_NFILE]; /* The pipe structures */
- static int Pipes_Inited = 0; /* Initialised ? */
- static int Unique_Pipe = 0;
-
- static PIPE *_p_save_entry (char *, char *);
- static int _p_run (char *);
- static int _p_reset_entry (PIPE *, int);
- static PIPE *_p_get_entry (FILE *);
- static int _p_onexit (void);
-
- /* Set up a pipe structure */
-
- static PIPE *_p_save_entry (prog, mode)
- char *prog;
- char *mode;
- {
- FILE *fp; /* File handler */
- PIPE *pp; /* Pipe handler structure */
- char tmpfile[NAME_MAX + PATH_MAX + 2];
- char *tmpdir; /* Points to directory prefix of pipe */
- char s_mode = *mode;
-
- /* Find out where we should put temporary files */
-
- if ((tmpdir = getenv ("TMPDIR")) == (char *) NULL)
- tmpdir = getenv ("TMP");
-
- /* Use temporary directory if available */
-
- if (tmpdir == (char *)NULL)
- tmpdir = ".";
-
- /* Get a unique pipe file name */
-
- sprintf (tmpfile, "%s/pipe%.4x.tmp", tmpdir, Unique_Pipe++);
- unlink (tmpfile);
-
- /* Create the pipe */
-
- *mode = 'w';
- fp = fopen (tmpfile, mode);
- *mode = s_mode;
-
- if (fp == (FILE *) NULL)
- return (PIPE *)NULL;
-
- /* Create the PIPE entry */
-
- if ((pp = _p_get_entry ((FILE *)NULL)) == (PIPE *)NULL)
- {
- fclose (fp);
- unlink (tmpfile);
- errno = EMFILE;
- return (PIPE *)NULL;
- }
-
- /* Set up the entry */
-
- pp->p_fp = fp;
- pp->p_write = *mode;
- pp->p_process = strdup (prog);
- pp->p_file = strdup (tmpfile);
-
- /* Check for errors */
-
- if ((pp->p_process == (char *)NULL) || (pp->p_file == (char *)NULL))
- {
- _p_reset_entry (pp, 1);
- errno = ENOMEM;
- return (FILE *)NULL;
- }
-
- return pp;
- }
-
- /* Execute command via SHELL or COMSPEC */
-
- static int _p_run (command)
- char *command;
- {
- char *shell; /* Command processor */
- char *shellpath; /* Full command processor path */
- char *bp; /* Generic string pointer */
- char *dash = "/c";
-
- /* Determine the command processor */
-
- if (((shell = getenv ("SHELL")) == (char *) NULL) &&
- ((shell = getenv ("COMSPEC")) == (char *) NULL))
- shell = "command.com";
-
- shellpath = strlwr (shell);
-
- /* Strip off any leading backslash directories */
-
- if ((shell = strrchr (shellpath, '\\')) != (char *)NULL)
- ++shell;
-
- else
- shell = shellpath;
-
- /* Strip off any leading slash directories */
-
- if ((bp = strrchr (shell, '/')) != (char *)NULL)
- shell = ++bp;
-
- if (strcmp (shell, "command.com"))
- *dash = '/';
-
- /* Run the program */
-
- return spawnl (P_WAIT, shellpath, shell, dash, command, (char *) NULL);
- }
-
- /* resetpipe: Private routine to cancel a pipe */
-
- static int _p_reset_entry (pp, mode)
- PIPE *pp;
- int mode;
- {
- int result = (!mode) ? 0 : -1;
- int serrno = errno;
-
- /* Close the pipe */
-
- fclose (pp->p_fp);
-
- /* Free up memory */
-
- if (pp->p_file != (char *)NULL)
- {
- result = unlink (pp->p_file);
-
- if (!mode)
- serrno = errno;
-
- else
- result = -1;
-
- free (pp->p_file);
- }
-
- if (pp->p_process != (char *)NULL)
- free (pp->p_process);
-
- memset (pp, 0, sizeof (PIPE));
-
- /* Return error code */
-
- errno = serrno;
- return result;
- }
-
- /* Find a free entry */
-
- static PIPE *_p_get_entry (fp)
- FILE *fp;
- {
- int i;
-
- for (i = 0; i < _NFILE; i++)
- {
- if (P_list[i].p_fp == fp)
- return &P_list[i];
- }
-
- return (PIPE *)NULL;
- }
-
-
- /* popen: open a pipe */
-
- FILE *popen (command, type)
- char *command; /* The command to be run */
- char *type; /* "w" or "r" */
- {
- int old_stdout;
- PIPE *pp;
-
- /* Initialise the pipe structure */
-
- if (!Pipes_Inited)
- {
- memset (&P_list[0], 0, sizeof (P_list));
- Pipes_Inited = 1;
-
- if (onexit (_p_onexit) == (onexit_t)NULL)
- return (FILE *)NULL;
- }
-
- /* For write style pipe, pclose handles program execution */
-
- if (*type == 'w')
- return ((pp = _p_save_entry (command, type)) == (PIPE *)NULL)
- ? (FILE *)NULL : pp->p_fp;
-
- /* read pipe must create tmp file, set up stdout to point to the temp
- * file, and run the program. note that if the pipe file cannot be
- * opened, it'll return a condition indicating pipe failure, which is
- * fine.
- */
-
- else if (*type == 'r')
- {
- if ((pp = _p_save_entry (command, type)) == (PIPE *)NULL)
- return (FILE *)NULL;
-
- /* Save the stdout file descriptor, dup the pipe onto standard out,
- * execute the command, close the pipe and re-open it
- */
-
- if (((old_stdout = dup (fileno(stdout))) < 0) ||
- (dup2 (fileno (pp->p_fp), fileno(stdout)) < 0) ||
- ((pp->p_status = _p_run (command)) < 0) ||
- (fclose (pp->p_fp) < 0) ||
- (dup2 (old_stdout, fileno (stdout)) < 0) ||
- ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL))
- {
- _p_reset_entry (pp, 1);
- return (FILE *)NULL;
- }
-
- else
- return pp->p_fp;
- }
-
- /* screwy call or unsupported type */
-
- errno = EINVAL;
- return (FILE *)NULL;
- }
-
- /* close a pipe */
-
- int pclose (fp)
- FILE *fp;
- {
- PIPE *pp; /* Current pipe structure */
- int old_stdin; /* Where our stdin points now */
-
- if ((pp = _p_get_entry (fp)) == (PIPE *)NULL)
- {
- errno = EBADF;
- return -1;
- }
-
- if (fclose (pp->p_fp) < 0)
- return _p_reset_entry (pp, 1);
-
- /* Open the pipe in read mode, Save stdin file descriptor, copy pipe file
- * descriptor to stdin, execute the command, and then restore stdin
- */
-
- if ((pp->p_write == 'w') &&
- ( ((pp->p_fp = fopen (pp->p_file, "r")) == (FILE *)NULL) ||
- ((old_stdin = dup (fileno (stdin))) < 0) ||
- (dup2 (fileno (pp->p_fp), fileno (stdin)) < 0) ||
- ((pp->p_status = _p_run (pp->p_process)) < 0) ||
- (fclose (pp->p_fp) < 0) ||
- (dup2 (old_stdin, fileno (stdin)) < 0)
- ))
- return _p_reset_entry (pp, 1);
-
- /* Close the temp file and remove it */
-
- return _p_reset_entry (pp, 0);
- }
-
- /* Clean up on exit, in case a pipe has not been processed */
-
- static int _p_onexit ()
- {
- int i;
-
- for (i = 0; i < _NFILE; i++)
- {
- if (P_list[i].p_fp != (FILE *)NULL)
- pclose (P_list[i].p_fp);
- }
-
- return 0;
- }
-