1 /* Implement unix popen and pclose in vms by using mailboxes
2 and lib$spawn.
3 17-APR-91 -GJC@MITECH.COM version 1.0
4 */
5
6 #include <stdio.h>
7 #include <descrip.h>
8 #include <ssdef.h>
9 #include <string.h>
10
11 FILE *popen();
12 int pclose();
13
14 globalvalue CLI$M_NOWAIT;
15
16 void p_describe(); /* a non-unix function */
17
18 static struct dsc$descriptor *set_dsc_cst();
19 static int create_mbx();
20
21 #define mailbox_size (512)
22 #define mailbox_byte_quota (3*mailbox_size)
23 #define mailbox_protection_mask (0x0000F000)
24
25 struct popen_cell
26 {FILE *fp;
27 char *mbx_name;
28 short mbx_chan;
29 long pid;
30 long completed;
31 long comp_status;
32 struct popen_cell *next;
33 struct popen_cell *prev;};
34
35 static struct popen_cell *popen_list = NULL;
36
find_popen_cell(fp)37 static struct popen_cell *find_popen_cell(fp)
38 FILE *fp;
39 {struct popen_cell *l;
40 for(l=popen_list;l != NULL; l = l->next)
41 if (l->fp == fp) return(l);
42 return(NULL);}
43
p_describe(fp)44 void p_describe(fp)
45 FILE *fp;
46 {struct popen_cell *cell;
47 if (!(cell = find_popen_cell(fp)))
48 {printf("File pointer is not from popen, or it has been closed\n");
49 return;}
50 printf("FILE *fp = %08X\n",cell->fp);
51 printf("char *mbx_name = %s\n",cell->mbx_name);
52 printf("short mbx_chan = %d\n",cell->mbx_chan);
53 printf("long pid = %08X\n",cell->pid);
54 printf("long completed = %d\n",cell->completed);
55 printf("long comp_status = %d\n",cell->comp_status);
56 printf("struct popen_cell *next = %08X\n",cell->next);
57 printf("struct popen_cell *prev = %08X\n",cell->prev);}
58
proc_exit_ast(cell)59 static void proc_exit_ast(cell)
60 struct popen_cell *cell;
61 {cell->completed = 1;}
62
pclose_cleanup(cell)63 static void pclose_cleanup(cell)
64 struct popen_cell *cell;
65 {sys$dassgn(cell->mbx_chan);
66 free(cell->mbx_name);
67 if (!cell->completed)
68 sys$delprc(&cell->pid,0);
69 memset(cell,0,sizeof(struct popen_cell));
70 free(cell);}
71
pclose_delq(cell)72 static void pclose_delq(cell)
73 struct popen_cell *cell;
74 {if (cell->prev)
75 {cell->prev->next = cell->next;
76 if (cell->next)
77 cell->next->prev = cell->prev;}
78 else
79 {popen_list = cell->next;
80 if (cell->next)
81 cell->next->prev = NULL;}}
82
popen_push(cell)83 static void popen_push(cell)
84 struct popen_cell *cell;
85 {if (popen_list)
86 popen_list->prev = cell;
87 cell->prev = NULL;
88 cell->next = popen_list;
89 popen_list = cell;}
90
pclose(fp)91 int pclose(fp)
92 FILE *fp;
93 {int i;
94 struct popen_cell *cell;
95 i = fclose(fp);
96 if (cell = find_popen_cell(fp))
97 {pclose_delq(cell);
98 pclose_cleanup(cell);}
99 return(i);}
100
popen(command,mode)101 FILE *popen(command,mode)
102 char *command,*mode;
103 {char *temp;
104 struct popen_cell *cell;
105 int readp,n,mask,ret;
106 char *name,*prompt,*in,*out;
107 struct dsc$descriptor comm_d,in_d,out_d,name_d,prompt_d;
108
109 if (strcmp(mode,"r") == 0)
110 readp = 1;
111 else if (strcmp(mode,"w") == 0)
112 readp = 0;
113 else
114 return(NULL);
115
116 temp = mktemp("POPEN_MB_XXXXXXXXXX");
117 n = strlen(temp);
118 cell = (struct popen_cell *) malloc(sizeof(struct popen_cell));
119 cell->mbx_name = (char *) malloc(n+1);
120 strcpy(cell->mbx_name,temp);
121 if ((cell->mbx_chan = create_mbx(cell->mbx_name)) < 0)
122 {cell->completed = 1;
123 pclose_cleanup(cell);
124 return(NULL);}
125
126 if (readp)
127 {in = "NL:";
128 out = cell->mbx_name;}
129 else
130 {in = cell->mbx_name;
131 out = "NL:";}
132
133 name = 0;
134 prompt = 0;
135 mask = CLI$M_NOWAIT;
136
137 cell->completed = 0;
138
139 ret = lib$spawn((command) ? set_dsc_cst(&comm_d,command) : 0,
140 (in) ? set_dsc_cst(&in_d,in) : 0,
141 (out) ? set_dsc_cst(&out_d,out) : 0,
142 &mask,
143 (name) ? set_dsc_cst(&name_d,name) : 0,
144 &cell->pid,
145 &cell->comp_status,
146 0, /* event flag */
147 proc_exit_ast,
148 cell,
149 (prompt) ? set_dsc_cst(&prompt_d,prompt) : 0,
150 0 /* cli */
151 );
152
153 if (ret != SS$_NORMAL)
154 {cell->completed = 1;
155 pclose_cleanup(cell);
156 return(NULL);}
157
158 if (!(cell->fp = fopen(cell->mbx_name,mode)))
159 {pclose_cleanup(cell);
160 return(NULL);}
161
162 popen_push(cell);
163
164 return(cell->fp);}
165
set_dsc_cst(x,buff)166 static struct dsc$descriptor *set_dsc_cst(x,buff)
167 struct dsc$descriptor *x;
168 char *buff;
169 {(*x).dsc$w_length = strlen(buff);
170 (*x).dsc$a_pointer = buff;
171 (*x).dsc$b_class = DSC$K_CLASS_S;
172 (*x).dsc$b_dtype = DSC$K_DTYPE_T;
173 return(x);}
174
create_mbx(name)175 static int create_mbx(name)
176 char *name;
177 {short chan;
178 int prmflg,maxmsg,bufquo,promsk,acmode,iflag,retval;
179 struct dsc$descriptor lognam;
180 prmflg = 0;
181 maxmsg = mailbox_size;
182 bufquo = mailbox_byte_quota;
183 promsk = mailbox_protection_mask;
184 acmode = 0;
185 set_dsc_cst(&lognam,name);
186 retval = sys$crembx(prmflg,&chan,maxmsg,bufquo,promsk,acmode,&lognam);
187 if (retval != SS$_NORMAL) return(-1);
188 return(chan);}
189