2 * The Regina Rexx Interpreter
3 * Copyright (C) 1992 Anders Christensen <anders@pvv.unit.no>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <processes.h>
26 #include <climsgdef.h>
36 unsigned short status
;
44 /* #define VMS_DEBUG */
46 #define MAX(a,b) (((a)>(b))?(a):(b))
47 #define MIN(a,b) (((a)<(b))?(a):(b))
49 #define MAX_SYM_LENGTH 256
51 typedef struct { /* vms_tsd: static variables of this module (thread-safe) */
56 volatile int comp_stat
;
59 char buffer
[BUFSIZE
] ;
60 struct mbox_status ostat
;
61 struct mbox_status istat
;
63 } vms_tsd_t
; /* thread-specific but only needed by this module. see
68 /* init_vms initializes the module.
69 * Currently, we set up the thread specific data.
70 * The function returns 1 on success, 0 if memory is short.
72 int init_vms( tsd_t
*TSD
)
76 if (TSD
->vms_tsd
!= NULL
)
79 if ((vt
= TSD
->vms_tsd
= MallocTSD(sizeof(vms_tsd_t
))) == NULL
)
81 memset(vt
,0,sizeof(vms_tsd_t
)); /* correct for all values */
87 * At least with OpenVMS 7.3-1 on Alpha, the Posix way seems to work.
88 * So there is no need to redirect on (now) bogus code.
89 * But I keep the code here in case I didn't see something.
92 static void vms_error (const int error_code
)
94 LIB$
SIGNAL(error_code
);
98 static void complain (const tsd_t
*TSD
, const int rc
)
104 printf ("About to complain ... rc=%d, pid=%d, ochan=%d, ichan=%d\n",
105 rc
, vt
->pid
, vt
->ochan
, vt
->ichan
) ;
108 if ((rc
!= SS$_NORMAL
) && vt
->pid
)
109 sys$
delprc( &vt
->pid
, NULL
), vt
->pid
=0 ;
112 if (vt->ochan) sys$dassgn ((short)vt->ochan), vt->ochan=0 ;
114 if (vt
->ichan
) sys$
dassgn ((short)vt
->ichan
), vt
->ichan
=0 ;
117 printf( "No more complains left ...about to give error\n" ) ;
120 if (rc
&& (rc
!= SS$_NORMAL
)) vms_error (rc
) ;
123 printf ("Exiting complain\n") ;
129 static void read_in_ast( const int read
)
136 TSD
= __regina_get_tsd(); /* This seems to be a system callback function.
137 * The TSD must be fetched directly.
142 switch ( vt
->ostat
.status
) {
144 if (vt
->ostat
.size
>= BUFSIZE
)
145 complain( TSD
, SS$_NORMAL
) ;
146 ptr
= Str_makeTSD( vt
->ostat
.size
) ;
147 ptr
= Str_ncatstrTSD( ptr
, vt
->buffer
, vt
->ostat
.size
) ;
148 tmp_stack( TSD
, ptr
, 1 ) ;
152 rc
= sys$
dassgn( (short)vt
->ochan
) ;
153 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
155 rc
= sys$
setef( vt
->oflag
) ;
156 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
161 "sys$qio() return unexpected status value %d\n",
164 complain( TSD
, rc
) ;
169 rc
= sys$
qio(0, (short)vt
->ochan
, IO$_READVBLK
, &vt
->ostat
,
171 vt
->buffer
, BUFSIZE
, 0, 0, 0, 0 ) ;
177 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
183 static void write_out_ast()
189 TSD
= __regina_get_tsd(); /* This seems to be a system callback function.
190 * The TSD must be fetched directly.
200 FreeTSD( vt
->kill
) ;
204 if (! stack_empty( TSD
)) {
205 vt
->kill
= popline( TSD
, NULL
, NULL
, 0 ) ;
207 if (!vt
->ichan
) return ;
208 rc
= sys$
qio(0, vt
->ichan
, IO$_WRITEVBLK
, &vt
->istat
,
209 write_out_ast
, 0, vt
->kill
->value
, Str_len(vt
->kill
), 0, 0,
216 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
218 if (vt
->dead
++ >= 5) {
222 if (!vt
->ichan
) return ;
223 rc
= sys$
qio(0, vt
->ichan
, IO$_WRITEOF
, &vt
->istat
,
224 write_out_ast
, 0, 0, 0, 0, 0, 0, 0 ) ;
225 if (rc
== SS$_IVCHAN
) return ;
226 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
229 if (--vt
->queue
) goto start
;
234 #define in (io_flags == REDIR_INPUT)
235 #define out (io_flags == REDIR_OUTPUT)
236 #define fout (io_flags == REDIR_OUTFIFO)
237 int vms_do_command( tsd_t
*TSD
, const streng
*cmd
, int io_flags
, environment
*env
, Queue
*redir
)
239 struct dsc$descriptor_s name
, input
, output
, prc_name
;
240 int fdin
[2], fdout
[2], strval
[2], strval2
[2], lim
=0, max
=0 ;
241 int rc
, rc1
, child
, status
, fin
, eflag
, olen
, ilen
;
242 char line
[128], obuf
[32], buf2
[32], ibuf
[32], nbuf
[32] ;
243 struct mbox_status stat
;
247 name
.dsc$w_length
= Str_len( cmd
) ;
248 name
.dsc$b_dtype
= DSC$K_DTYPE_T
;
249 name
.dsc$b_class
= DSC$K_CLASS_S
;
250 name
.dsc$a_pointer
= (char *)cmd
->value
;
252 vt
->ichan
= vt
->ochan
= 0 ;
254 vt
->dead
= vt
->queue
= 0 ;
255 rc
= sys$
crembx(0, &vt
->ichan
, BUFSIZE
, BUFSIZE
*NUMBUFS
, 0, 0, 0) ;
256 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
257 strval
[0] = sizeof(ibuf
) ;
258 strval
[1] = (int) ibuf
;
259 rc
= lib$
getdvi( &DVI$_DEVNAM
, &vt
->ichan
, 0, 0, strval
, &ilen
) ;
260 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
262 input
.dsc$w_length
= ilen
;
263 input
.dsc$b_dtype
= DSC$K_DTYPE_T
;
264 input
.dsc$b_class
= DSC$K_CLASS_S
;
265 input
.dsc$a_pointer
= ibuf
;
270 rc
= sys$
crembx(0,&vt
->ochan
,BUFSIZE
,BUFSIZE
*NUMBUFS
,0,0,0) ;
271 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
274 printf( "sys$crembx() ochan=%d, rc=%d\n", vt
->ochan
, rc
) ;
277 strval
[0] = sizeof(obuf
) ;
278 strval
[1] = (int) obuf
;
279 rc
=lib$
getdvi( &DVI$_DEVNAM
, &vt
->ochan
, 0, 0, strval
, &olen
) ;
280 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
283 printf( "lib$getdvi() name=(%d) <%s>\n", olen
, obuf
) ;
286 output
.dsc$w_length
= olen
;
287 output
.dsc$b_dtype
= DSC$K_DTYPE_T
;
288 output
.dsc$b_class
= DSC$K_CLASS_S
;
289 output
.dsc$a_pointer
= obuf
;
292 sprintf( nbuf
, "REXX-%d", getpid()) ;
293 prc_name
.dsc$w_length
= strlen( nbuf
) ;
294 prc_name
.dsc$b_dtype
= DSC$K_DTYPE_T
;
295 prc_name
.dsc$b_class
= DSC$K_CLASS_S
;
296 prc_name
.dsc$a_pointer
= nbuf
;
298 if (io_flags
== REDIR_OUTPUT
|| io_flags
== REDIR_OUTFIFO
) {
299 rc
= lib$
get_ef( &vt
->oflag
) ;
300 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
302 rc
= sys$
clref( vt
->oflag
) ;
303 /* if (rc != SS$_NORMAL) complain( TSD, rc ) ; */
306 rc
= lib$
get_ef( &eflag
) ;
307 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
309 rc
= sys$
clref( eflag
) ;
310 /* if (rc != SS$_NORMAL) complain( TSD, rc ) ; */
313 rc
= lib$
spawn( &name
,
314 ((in
) ? &input
: NULL
),
315 ((out
|| fout
) ? &output
: NULL
),
316 &CLI$M_NOWAIT
, &prc_name
, &vt
->pid
, &vt
->comp_stat
,
317 &eflag
, NULL
, NULL
, NULL
, NULL
) ;
319 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
322 printf( "lib$spawn() rc=%d\n", rc
) ;
325 if (in
) write_out_ast() ;
327 if (out
|| fout
) read_in_ast( 0 ) ;
330 printf( "Input and output asts started, synching on process\n" ) ;
333 rc
= sys$
synch( eflag
, NULL
) ;
336 printf( "sys$synch() rc=%d, ochan=%d\n", rc
, vt
->ochan
) ;
340 rc
= sys$
dassgn( (short)vt
->ichan
) ;
342 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
345 if (io_flags
== REDIR_OUTPUT
|| io_flags
== REDIR_OUTFIFO
) {
346 rc
= sys$
synch( vt
->oflag
, NULL
) ;
348 printf( "Warning ... output channel still exists ochan=%d\n",
351 if (rc
!= SS$_NORMAL
)
352 complain( TSD
, rc
) ;
354 rc
= lib$
free_ef( &vt
->oflag
) ;
355 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
358 rc
= lib$
free_ef( &eflag
) ;
359 if (rc
!= SS$_NORMAL
) complain( TSD
, rc
) ;
362 * Warning, kludge ahead!!! When a process under VMS exits, it
363 * seems like there is a little delay until the PRCCNT (process
364 * count) is decremented. So ... if we just continues without
365 * sync'ing up against the PRCCNT, we might get a 'quota exceeded'
366 * on the next command (if it is started very soon)
369 lib$
getjpi( &JPI$_PRCLM
, 0, 0, &max
, 0, 0 ) ;
370 for (lim
=max
; lim
>=max
; )
371 lib$
getjpi( &JPI$_PRCCNT
, 0, 0, &lim
, 0, 0 ) ;
377 flush_stack( TSD
, io_flags
) ;
381 * I have no idea _why_, but bit 28 is sometimes set in the comp_stat.
382 * Manuals indicate that this is an internal field, but at least it
383 * kills checking against the predefined symbols, so I strip it away.
384 * This should most probably have been handled differently, can someone
385 * educate me on this? .... please???
387 if ((vt
->comp_stat
& 0x0fffffff) == CLI$_NORMAL
) vt
->comp_stat
= SS$_NORMAL
;
388 return (((vt
->comp_stat
& 0x0fffffff)==SS$_NORMAL
) ? 0 : vt
->comp_stat
) ;
392 int vms_killproc( tsd_t
*TSD
)
398 sys$
delprc( &vt
->pid
, NULL
) ;
404 streng
*vms_resolv_symbol( tsd_t
*TSD
, streng
*name
, streng
*new, streng
*pool
)
406 struct dsc$descriptor_s sym_name
, sym_val
, new_val
;
407 char buffer
[MAX_SYM_LENGTH
] ;
408 unsigned int length
=0 ;
414 sym_name
.dsc$w_length
= Str_len( name
) ;
415 sym_name
.dsc$b_dtype
= DSC$K_DTYPE_T
;
416 sym_name
.dsc$b_class
= DSC$K_CLASS_S
;
417 sym_name
.dsc$a_pointer
= name
->value
;
420 new_val
.dsc$w_length
= Str_len( new ) ;
421 new_val
.dsc$b_dtype
= DSC$K_DTYPE_T
;
422 new_val
.dsc$b_class
= DSC$K_CLASS_S
;
423 new_val
.dsc$a_pointer
= new->value
;
426 sym_val
.dsc$w_length
= MAX_SYM_LENGTH
;
427 sym_val
.dsc$b_dtype
= DSC$K_DTYPE_T
;
428 sym_val
.dsc$b_class
= DSC$K_CLASS_S
;
429 sym_val
.dsc$a_pointer
= buffer
;
431 if (strncmp( pool
->value
, "SYMBOL", MAX(6,Str_len(pool
))) ||
432 strncmp( pool
->value
, "SYSTEM", MAX(6,Str_len(pool
))))
434 rc
= lib$
get_symbol( &sym_name
, &sym_val
, &length
) ;
436 lib$
set_symbol( &sym_name
, &new_val
) ;
438 else if (strncmp( pool
->value
, "LOGICAL", MAX(7, Str_len(pool
))))
440 /* rc = lib$get_logical( ... ) */
442 lib$
set_symbol( &sym_name
, &new_val
) ;
444 lib$
delete_logical( &sym_name
) ;
449 old
= Str_makeTSD( length
) ;
450 Str_ncatstrTSD( old
, buffer
, length
) ;