/* Implement unix popen and pclose in vms by using mailboxes
and lib$spawn.
17-APR-91 -GJC@MITECH.COM version 1.0
*/
#include <stdio.h>
#include <descrip.h>
#include <ssdef.h>
#include <string.h>
FILE *popen();
int pclose();
globalvalue CLI$M_NOWAIT;
void p_describe(); /* a non-unix function */
static struct dsc$descriptor *set_dsc_cst();
static int create_mbx();
#define mailbox_size (512)
#define mailbox_byte_quota (3*mailbox_size)
#define mailbox_protection_mask (0x0000F000)
struct popen_cell
{FILE *fp;
char *mbx_name;
short mbx_chan;
long pid;
long completed;
long comp_status;
struct popen_cell *next;
struct popen_cell *prev;};
static struct popen_cell *popen_list = NULL;
static struct popen_cell *find_popen_cell(fp)
FILE *fp;
{struct popen_cell *l;
for(l=popen_list;l != NULL; l = l->next)
if (l->fp == fp) return(l);
return(NULL);}
void p_describe(fp)
FILE *fp;
{struct popen_cell *cell;
if (!(cell = find_popen_cell(fp)))
{printf("File pointer is not from popen, or it has been closed\n");
return;}
printf("FILE *fp = %08X\n",cell->fp);
printf("char *mbx_name = %s\n",cell->mbx_name);
printf("short mbx_chan = %d\n",cell->mbx_chan);
printf("long pid = %08X\n",cell->pid);
printf("long completed = %d\n",cell->completed);
printf("long comp_status = %d\n",cell->comp_status);
printf("struct popen_cell *next = %08X\n",cell->next);
printf("struct popen_cell *prev = %08X\n",cell->prev);}
static void proc_exit_ast(cell)
struct popen_cell *cell;
{cell->completed = 1;}
static void pclose_cleanup(cell)
struct popen_cell *cell;
{sys$dassgn(cell->mbx_chan);
free(cell->mbx_name);
if (!cell->completed)
sys$delprc(&cell->pid,0);
memset(cell,0,sizeof(struct popen_cell));
free(cell);}
static void pclose_delq(cell)
struct popen_cell *cell;
{if (cell->prev)
{cell->prev->next = cell->next;
if (cell->next)
cell->next->prev = cell->prev;}
else
{popen_list = cell->next;
if (cell->next)
cell->next->prev = NULL;}}
static void popen_push(cell)
struct popen_cell *cell;
{if (popen_list)
popen_list->prev = cell;
cell->prev = NULL;
cell->next = popen_list;
popen_list = cell;}
int pclose(fp)
FILE *fp;
{int i;
struct popen_cell *cell;
i = fclose(fp);
if (cell = find_popen_cell(fp))
{pclose_delq(cell);
pclose_cleanup(cell);}
return(i);}
FILE *popen(command,mode)
char *command,*mode;
{char *temp;
struct popen_cell *cell;
int readp,n,mask,ret;
char *name,*prompt,*in,*out;
struct dsc$descriptor comm_d,in_d,out_d,name_d,prompt_d;
if (strcmp(mode,"r") == 0)
readp = 1;
else if (strcmp(mode,"w") == 0)
readp = 0;
else
return(NULL);
temp = mktemp("POPEN_MB_XXXXXXXXXX");
n = strlen(temp);
cell = (struct popen_cell *) malloc(sizeof(struct popen_cell));
cell->mbx_name = (char *) malloc(n+1);
strcpy(cell->mbx_name,temp);
if ((cell->mbx_chan = create_mbx(cell->mbx_name)) < 0)
{cell->completed = 1;
pclose_cleanup(cell);
return(NULL);}
if (readp)
{in = "NL:";
out = cell->mbx_name;}
else
{in = cell->mbx_name;
out = "NL:";}
name = 0;
prompt = 0;
mask = CLI$M_NOWAIT;
cell->completed = 0;
ret = lib$spawn((command) ? set_dsc_cst(&comm_d,command) : 0,
(in) ? set_dsc_cst(&in_d,in) : 0,
(out) ? set_dsc_cst(&out_d,out) : 0,
&mask,
(name) ? set_dsc_cst(&name_d,name) : 0,
&cell->pid,
&cell->comp_status,
0, /* event flag */
proc_exit_ast,
cell,
(prompt) ? set_dsc_cst(&prompt_d,prompt) : 0,
0 /* cli */
);
if (ret != SS$_NORMAL)
{cell->completed = 1;
pclose_cleanup(cell);
return(NULL);}
if (!(cell->fp = fopen(cell->mbx_name,mode)))
{pclose_cleanup(cell);
return(NULL);}
popen_push(cell);
return(cell->fp);}
static struct dsc$descriptor *set_dsc_cst(x,buff)
struct dsc$descriptor *x;
char *buff;
{(*x).dsc$w_length = strlen(buff);
(*x).dsc$a_pointer = buff;
(*x).dsc$b_class = DSC$K_CLASS_S;
(*x).dsc$b_dtype = DSC$K_DTYPE_T;
return(x);}
static int create_mbx(name)
char *name;
{short chan;
int prmflg,maxmsg,bufquo,promsk,acmode,iflag,retval;
struct dsc$descriptor lognam;
prmflg = 0;
maxmsg = mailbox_size;
bufquo = mailbox_byte_quota;
promsk = mailbox_protection_mask;
acmode = 0;
set_dsc_cst(&lognam,name);
retval = sys$crembx(prmflg,&chan,maxmsg,bufquo,promsk,acmode,&lognam);
if (retval != SS$_NORMAL) return(-1);
return(chan);}
syntax highlighted by Code2HTML, v. 0.9.1