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