#ifndef __VMS_VER
#define __VMS_VER 0
#endif
#ifndef __DECC_VER
#define __DECC_VER 0
#endif
#if __VMS_VER < 70200000 || __DECC_VER < 50700000
#define MODULE PIPE
#define VERSION "V1.5"
#ifdef __DECC
#pragma module MODULE VERSION
#else
#ifdef VAXC
#module MODULE VERSION
#endif
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iodef.h>
#include <ssdef.h>
#include <syidef.h>
#include <clidef.h>
#include <stsdef.h>
#include <dvidef.h>
#include <nam.h>
#include <descrip.h>
#include <errno.h>
#include <file.h>
#include <lib$routines.h>
#include <starlet.h>
#include <setjmp.h>
#include "vms-types.h"
struct PIPE
{
struct PIPE *next;
struct PIPE *prev;
struct PIPE *self;
int mode;
long status;
struct IOSB iosb;
FILE *file;
int pid;
short chan;
jmp_buf jmpbuf;
int has_jmpbuf;
};
static struct PIPE *phead = NULL, *ptail = NULL;
static unsigned char evf = 1;
static int
pwait (status)
int status;
{
struct IOSB iosb;
struct PIPE *this;
int ret = 0;
this = phead;
while (this)
{
if (this->self != this)
{
ret = -1;
continue;
}
if (!this->iosb.status)
{
fflush (this->file);
if (this->mode == O_WRONLY)
sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
0, 0, 0, 0, 0, 0, 0, 0);
fclose (this->file);
sys$synch (evf, &this->iosb);
}
else
fclose(this->file);
sys$dassgn (this->chan);
this = this->next;
}
return ret;
}
int
pclose (stream)
FILE *stream;
{
struct IOSB iosb;
struct PIPE *this = phead;
while (this && this->self == this && this->file != stream)
this = this->next;
if (!this)
return -1;
else if (this->self != this)
return -2;
if (!this->iosb.status)
{
fflush (this->file);
if (this->mode == O_WRONLY)
sys$qio (0, this->chan, IO$_WRITEOF, &iosb,
0, 0, 0, 0, 0, 0, 0, 0);
fclose (this->file);
sys$synch (evf, &this->iosb);
}
else
fclose (this->file);
sys$dassgn (this->chan);
if (this == ptail)
ptail = this->prev;
if (this == phead)
phead = this->next;
if (this->prev)
this->prev->next = this->next;
if (this->next)
this->next->prev = this->prev;
free (this);
if (this->status & STS$M_SUCCESS != STS$M_SUCCESS)
return this->status;
else
return 0;
}
void
pdone (this)
struct PIPE *this;
{
struct IOSB iosb;
if (this->self != this)
return;
this->iosb.status = 1;
this->pid = 0;
if (this->has_jmpbuf)
{
this->has_jmpbuf = 0;
longjmp (this->jmpbuf, 1);
}
}
int
pipe_set_fd_jmpbuf (fd, jmpbuf)
int fd;
jmp_buf jmpbuf;
{
struct PIPE *this = phead;
while (this)
if (fileno (this->file) == fd)
{
memcpy (this->jmpbuf, jmpbuf, sizeof (jmp_buf));
this->has_jmpbuf = 1;
if (this->pid == 0)
{
this->has_jmpbuf = 0;
longjmp (this->jmpbuf, 1);
}
return 0;
}
else
this = this->next;
return 1;
}
pipe_unset_fd_jmpbuf (fd)
int fd;
{
struct PIPE *this = phead;
while (this)
if (fileno (this->file) == fd)
{
this->has_jmpbuf = 0;
return 0;
}
else
this = this->next;
return 1;
}
static struct EXHCB pexhcb = { 0, pwait, 1, &pexhcb.exh$l_status, 0 };
struct Vstring
{
short length;
char body[NAM$C_MAXRSS+1];
};
FILE *
popen (cmd, mode)
const char *cmd;
const char *mode;
{
int i, status, flags, mbxsize;
struct IOSB iosb;
struct dsc$descriptor_s cmddsc, mbxdsc;
struct Vstring mbxname = { sizeof(mbxname.body) };
struct itm$list3 mbxlist[2] = {
{ sizeof(mbxname.body)-1, DVI$_DEVNAM, &mbxname.body, &mbxname.length },
{ 0, 0, 0, 0} };
struct itm$list3 syilist[2] = {
{ sizeof(mbxsize), SYI$_MAXBUF, &mbxsize, (void *) 0 },
{ 0, 0, 0, 0} };
static int noExitHandler = 1;
struct PIPE *this;
this = (struct PIPE *) calloc (1, sizeof(struct PIPE));
if (!this)
{
errno = ENOMEM;
return NULL;
}
this->self = this;
status = sys$getsyiw(0, 0, 0, syilist, &iosb, 0, 0, 0);
if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
{
vaxc$errno = iosb.status;
errno = EVMSERR;
free (this);
perror ("popen, $GETSYIW failure for SYI$_MAXBUF");
return NULL;
}
if (mbxsize > 2048)
mbxsize = 2048;
status = sys$crembx (0, &this->chan, mbxsize, mbxsize, 0, 0, 0, 0);
if (status != SS$_NORMAL)
{
vaxc$errno = status;
errno = EVMSERR;
free (this);
perror ("popen, $CREMBX failure");
return NULL;
}
status = sys$getdviw (0, this->chan, 0, &mbxlist, &iosb, 0, 0, 0);
if (status != SS$_NORMAL && !(iosb.status & STS$M_SUCCESS))
{
vaxc$errno = iosb.status;
errno = EVMSERR;
sys$dassgn (this->chan);
free (this);
perror ("popen, $GETDVIW failure");
return NULL;
}
mbxname.body[mbxname.length] = 0;
mbxdsc.dsc$w_length = mbxname.length;
mbxdsc.dsc$b_dtype = DSC$K_DTYPE_T;
mbxdsc.dsc$b_class = DSC$K_CLASS_S;
mbxdsc.dsc$a_pointer = mbxname.body;
cmddsc.dsc$w_length = strlen(cmd);
cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
cmddsc.dsc$b_class = DSC$K_CLASS_S;
cmddsc.dsc$a_pointer = (char *)cmd;
flags = CLI$M_NOWAIT;
if (strcmp(mode,"w") == 0)
{
status = lib$spawn (&cmddsc, &mbxdsc, 0, &flags, 0, &this->pid,
&this->status, &evf, &pdone, this->self);
this->mode = O_WRONLY;
}
else
{
status = lib$spawn (&cmddsc, 0, &mbxdsc, &flags, 0, &this->pid,
&this->status, &evf, &pdone, this->self);
this->mode = O_RDONLY;
}
if (status != SS$_NORMAL)
{
vaxc$errno = status;
errno = EVMSERR;
sys$dassgn (this->chan);
free (this);
perror("popen, LIB$SPAWN failure");
return NULL;
}
if (noExitHandler)
{
status = sys$dclexh (&pexhcb);
if (status != SS$_NORMAL)
{
vaxc$errno = status;
errno = EVMSERR;
sys$dassgn (this->chan);
sys$delprc (&this->pid, 0);
free (this);
perror("popen, $DCLEXH failure");
return NULL;
}
noExitHandler = 0;
}
if (this->mode == O_WRONLY)
this->file = fopen (mbxname.body, "wb");
else
this->file = fopen (mbxname.body, "rb");
if (!this->file)
{
sys$dassgn (this->chan);
sys$delprc (this->pid);
free (this);
perror ("popen, fopen failure");
return NULL;
}
this->has_jmpbuf = 0;
if (phead)
{
ptail->next = this;
this->prev = ptail;
ptail = this;
}
else
phead = ptail = this;
return (this->file);
}
#ifdef TEST_PIPE
int
main (argc, argv)
int argc;
char **argv;
{
FILE *stdpipe;
char line[512];
while (1)
{
printf ("\nEnter a command to run >> ");
fgets (line, 511, stdin);
if (!strlen(line))
exit (1);
line[strlen(line)-1] = 0;
stdpipe = popen (line, "r");
if (!stdpipe)
{
fprintf (stderr, "popen failed.\n");
exit(44);
}
do {
fgets (line, 511, stdpipe);
fputs (line, stdout);
} while (!feof(stdpipe));
pclose (stdpipe);
}
}
#endif
#else
#pragma message disable EMPTYFILE
#endif