1 /* Interfaces to subprocesses on VMS.
2 Copyright (C) 1988, 1994 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 Event flag and `select' emulation
26 23 is the timer event flag
27 24-31 are reserved by VMS
41 extern Lisp_Object
call_process_cleanup ();
44 #define KEYBOARD_EVENT_FLAG 1
45 #define TIMER_EVENT_FLAG 23
47 static VMS_PROC_STUFF procList
[MAX_EVENT_FLAGS
+1];
52 Return the first event flag for keyboard input.
54 VMS_PROC_STUFF
*vs
= &procList
[KEYBOARD_EVENT_FLAG
];
58 return (vs
->eventFlag
);
61 get_timer_event_flag ()
64 Return the last event flag for use by timeouts
66 VMS_PROC_STUFF
*vs
= &procList
[TIMER_EVENT_FLAG
];
70 return (vs
->eventFlag
);
74 get_vms_process_stuff ()
77 Return a process_stuff structure
79 We use 1-23 as our event flags to simplify implementing
85 for (i
=1, vs
= procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
92 sys$
clref (vs
->eventFlag
);
96 return ((VMS_PROC_STUFF
*)0);
99 give_back_vms_process_stuff (vs
)
103 Return an event flag to our pool
111 get_vms_process_pointer (pid
)
115 Given a pid, return the VMS_STUFF pointer
120 /* Don't search the last one */
121 for (i
=0, vs
=procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
123 if (vs
->busy
&& vs
->pid
== pid
)
126 return ((VMS_PROC_STUFF
*)0);
129 start_vms_process_read (vs
)
133 Start an asynchronous read on a VMS process
134 We will catch up with the output sooner or later
139 status
= sys$
qio (vs
->eventFlag
, vs
->outputChan
, IO$_READVBLK
,
141 vs
->inputBuffer
, sizeof (vs
->inputBuffer
), 0, 0, 0, 0);
142 if (status
!= SS$_NORMAL
)
148 extern int waiting_for_ast
; /* in sysdep.c */
152 select (nDesc
, rdsc
, wdsc
, edsc
, timeOut
)
159 /* Emulate a select call
161 We know that we only use event flags 1-23
163 timeout == 100000 & bit 0 set means wait on keyboard input until
164 something shows up. If timeout == 0, we just read the event
165 flags and return what we find. */
170 int delta
= -10000000;
172 int timeout
= *timeOut
;
173 unsigned long mask
, readMask
, waitMask
;
176 readMask
= *rdsc
<< 1; /* Unix mask is shifted over 1 */
178 readMask
= 0; /* Must be a wait call */
180 sys$
clref (KEYBOARD_EVENT_FLAG
);
181 sys$
setast (0); /* Block interrupts */
182 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
); /* See what is set */
183 mask
&= readMask
; /* Just examine what we need */
185 { /* Nothing set, we must wait */
187 { /* Not just inspecting... */
188 if (!(timeout
== 100000 &&
189 readMask
== (1 << KEYBOARD_EVENT_FLAG
)))
191 lib$
emul (&timeout
, &delta
, &zero
, time
);
192 sys$
setimr (TIMER_EVENT_FLAG
, time
, 0, 1);
193 waitMask
= readMask
| (1 << TIMER_EVENT_FLAG
);
197 if (waitMask
& (1 << KEYBOARD_EVENT_FLAG
))
199 sys$
clref (KEYBOARD_EVENT_FLAG
);
200 waiting_for_ast
= 1; /* Only if reading from 0 */
203 sys$
wflor (KEYBOARD_EVENT_FLAG
, waitMask
);
205 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
);
206 if (readMask
& (1 << KEYBOARD_EVENT_FLAG
))
213 Count number of descriptors that are ready
217 *rdsc
= (mask
>> 1); /* Back to Unix format */
218 for (nfds
= 0; mask
; mask
>>= 1)
226 #define MAX_BUFF 1024
228 write_to_vms_process (vs
, buf
, len
)
234 Write something to a VMS process.
236 We have to map newlines to carriage returns for VMS.
238 char ourBuff
[MAX_BUFF
];
245 out
= map_nl_to_cr (buf
, ourBuff
, len
, MAX_BUFF
);
246 status
= sys$
qiow (0, vs
->inputChan
, IO$_WRITEVBLK
|IO$M_NOFORMAT
,
247 iosb
, 0, 0, ourBuff
, out
, 0, 0, 0, 0);
248 if (status
!= SS$_NORMAL
|| (status
= iosb
[0]) != SS$_NORMAL
)
250 error ("Could not write to subprocess: %x", status
);
259 map_nl_to_cr (in
, out
, maxIn
, maxOut
)
266 Copy `in' to `out' remapping `\n' to `\r'
271 for (o
=0; maxIn
-- > 0 && o
< maxOut
; o
++)
274 *out
++ = (c
== '\n') ? '\r' : c
;
279 clean_vms_buffer (buf
, len
)
284 Sanitize output from a VMS subprocess
294 if (c
== '\r' || c
== '\0')
306 For the CMU PTY driver
308 #define PTYNAME "PYA0:"
310 get_pty_channel (inDevName
, outDevName
, inChannel
, outChannel
)
316 int PartnerUnitNumber
;
329 d
.l
= strlen (PTYNAME
);
331 *inChannel
= 0; /* Should be `short' on VMS */
333 *inDevName
= *outDevName
= '\0';
334 status
= sys$
assign (&d
, inChannel
, 0, 0);
335 if (status
== SS$_NORMAL
)
337 *outChannel
= *inChannel
;
338 g
[0].BufLen
= sizeof (PartnerUnitNumber
);
339 g
[0].ItemCode
= DVI$_UNIT
;
340 g
[0].BufAddress
= &PartnerUnitNumber
;
341 g
[0].ItemLength
= (int *)0;
342 g
[1].BufLen
= g
[1].ItemCode
= 0;
343 status
= sys$
getdviw (0, *inChannel
, 0, &g
, 0, 0, 0, 0);
344 if (status
== SS$_NORMAL
)
346 sprintf (inDevName
, "_TPA%d:", PartnerUnitNumber
);
347 strcpy (outDevName
, inDevName
);
357 Return the current directory
370 s
= getenv ("SYS$DISK");
378 status
= sys$
setddir (0, &len
, &d
);
382 strcat (buf
, curdir
);
387 call_process_ast (vs
)
390 sys$
setef (vs
->eventFlag
);
394 child_setup (in
, out
, err
, new_argv
, env
)
396 register char **new_argv
;
399 /* ??? I suspect that maybe this shouldn't be done on VMS. */
401 /* Close Emacs's descriptors that this process should not have. */
402 close_process_descs ();
405 if (XTYPE (current_buffer
->directory
) == Lisp_String
)
406 chdir (XSTRING (current_buffer
->directory
)->data
);
409 DEFUN ("call-process", Fcall_process
, Scall_process
, 1, MANY
, 0,
410 "Call PROGRAM synchronously in a separate process.\n\
411 Program's input comes from file INFILE (nil means null device, `NLA0:').\n\
412 Insert output in BUFFER before point; t means current buffer;\n\
413 nil for BUFFER means discard it; 0 means discard and don't wait.\n\
414 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\
415 Remaining arguments are strings passed as command arguments to PROGRAM.\n\
416 This function waits for PROGRAM to terminate, unless BUFFER is 0;\n\
417 if you quit, the process is killed.")
420 register Lisp_Object
*args
;
422 Lisp_Object display
, buffer
, path
;
424 int inchannel
, outchannel
;
426 int call_process_ast ();
436 int SpawnFlags
= CLI$M_NOWAIT
;
438 VMS_PROC_STUFF
*get_vms_process_stuff ();
443 int count
= specpdl_ptr
- specpdl
;
444 register unsigned char **new_argv
;
445 struct buffer
*old
= current_buffer
;
447 CHECK_STRING (args
[0], 0);
449 if (nargs
<= 1 || NILP (args
[1]))
450 args
[1] = build_string ("NLA0:");
452 args
[1] = Fexpand_file_name (args
[1], current_buffer
->directory
);
454 CHECK_STRING (args
[1], 1);
457 register Lisp_Object tem
;
458 buffer
= tem
= args
[2];
461 else if (!(EQ (tem
, Qnil
) || EQ (tem
, Qt
)
462 || XFASTINT (tem
) == 0))
464 buffer
= Fget_buffer (tem
);
465 CHECK_BUFFER (buffer
, 2);
469 display
= nargs
>= 3 ? args
[3] : Qnil
;
473 if (args[0] == "*dcl*" then we need to skip pas the "-c",
474 else args[0] is the program to run.
480 if (strcmp (XSTRING (args
[0])->data
, "*dcl*") == 0)
490 len
= XSTRING (args
[arg0
])->size
+ 1;
491 for (i
= firstArg
; i
< nargs
; i
++)
493 CHECK_STRING (args
[i
], i
);
494 len
+= XSTRING (args
[i
])->size
+ 1;
496 new_argv
= alloca (len
);
497 strcpy (new_argv
, XSTRING (args
[arg0
])->data
);
498 for (i
= firstArg
; i
< nargs
; i
++)
500 strcat (new_argv
, " ");
501 strcat (new_argv
, XSTRING (args
[i
])->data
);
506 status
= get_pty_channel (inDevName
, outDevName
, &inchannel
, &outchannel
);
508 error ("Error getting PTY channel: %x", status
);
509 if (XTYPE (buffer
) == Lisp_Int
)
511 dout
.l
= strlen ("NLA0:");
516 dout
.l
= strlen (outDevName
);
520 vs
= get_vms_process_stuff ();
523 sys$
dassgn (inchannel
);
524 sys$
dassgn (outchannel
);
525 error ("Too many VMS processes");
527 vs
->inputChan
= inchannel
;
528 vs
->outputChan
= outchannel
;
531 filefd
= open (XSTRING (args
[1])->data
, O_RDONLY
, 0);
534 sys$
dassgn (inchannel
);
535 sys$
dassgn (outchannel
);
536 give_back_vms_process_stuff (vs
);
537 report_file_error ("Opening process input file", Fcons (args
[1], Qnil
));
542 din
.l
= XSTRING (args
[1])->size
;
543 din
.a
= XSTRING (args
[1])->data
;
546 Start a read on the process channel
548 if (XTYPE (buffer
) != Lisp_Int
)
550 start_vms_process_read (vs
);
551 SpawnFlags
= CLI$M_NOWAIT
;
557 On VMS we need to change the current directory
558 of the parent process before forking so that
559 the child inherit that directory. We remember
560 where we were before changing.
563 child_setup (0, 0, 0, 0, 0);
564 status
= lib$
spawn (&dcmd
, &din
, &dout
, &SpawnFlags
, 0, &vs
->pid
,
565 &vs
->exitStatus
, 0, call_process_ast
, vs
);
568 if (status
!= SS$_NORMAL
)
570 sys$
dassgn (inchannel
);
571 sys$
dassgn (outchannel
);
572 give_back_vms_process_stuff (vs
);
573 error ("Error calling LIB$SPAWN: %x", status
);
577 if (XTYPE (buffer
) == Lisp_Int
)
580 wait_without_blocking ();
585 if (!NILP (display
) && INTERACTIVE
)
586 prepare_menu_bars ();
588 record_unwind_protect (call_process_cleanup
,
589 Fcons (make_number (fd
[0]), make_number (pid
)));
592 if (XTYPE (buffer
) == Lisp_Buffer
)
593 Fset_buffer (buffer
);
600 sys$
waitfr (vs
->eventFlag
);
606 vs
->iosb
[1] = clean_vms_buffer (vs
->inputBuffer
, vs
->iosb
[1]);
607 InsCStr (vs
->inputBuffer
, vs
->iosb
[1]);
609 if (!NILP (display
) && INTERACTIVE
)
610 redisplay_preserve_echo_area ();
613 if (!start_vms_process_read (vs
))
614 break; /* The other side went away */
620 sys$
dassgn (inchannel
);
621 sys$
dassgn (outchannel
);
622 give_back_vms_process_stuff (vs
);
624 /* Wait for it to terminate, unless it already has. */
625 wait_for_termination (pid
);
629 set_current_buffer (old
);
631 return unbind_to (count
, Qnil
);
634 create_process (process
, new_argv
)
638 int pid
, inchannel
, outchannel
, forkin
, forkout
;
640 char in_dev_name
[65];
641 char out_dev_name
[65];
644 int spawn_flags
= CLI$M_NOWAIT
;
649 } din
, dout
, dprompt
, dcmd
;
651 VMS_PROC_STUFF
*get_vms_process_stuff ();
653 status
= get_pty_channel (in_dev_name
, out_dev_name
, &inchannel
, &outchannel
);
656 remove_process (process
);
657 error ("Error getting PTY channel: %x", status
);
659 dout
.l
= strlen (out_dev_name
);
660 dout
.a
= out_dev_name
;
661 dprompt
.l
= strlen (DCL_PROMPT
);
662 dprompt
.a
= DCL_PROMPT
;
664 if (strcmp (new_argv
, "*dcl*") == 0)
666 din
.l
= strlen (in_dev_name
);
673 din
.l
= strlen ("NLA0:");
675 dcmd
.l
= strlen (new_argv
);
679 /* Delay interrupts until we have a chance to store
680 the new fork's pid in its process structure */
683 vs
= get_vms_process_stuff ();
687 remove_process (process
);
688 error ("Too many VMS processes");
690 vs
->inputChan
= inchannel
;
691 vs
->outputChan
= outchannel
;
693 /* Start a read on the process channel */
694 start_vms_process_read (vs
);
696 /* Switch current directory so that the child inherits it. */
698 child_setup (0, 0, 0, 0, 0);
700 status
= lib$
spawn (&dcmd
, &din
, &dout
, &spawn_flags
, 0, &vs
->pid
,
701 &vs
->exitStatus
, 0, child_sig
, vs
, &dprompt
);
704 if (status
!= SS$_NORMAL
)
707 remove_process (process
);
708 error ("Error calling LIB$SPAWN: %x", status
);
710 vs
->pid
&= 0xffff; /* It needs to fit in a FASTINT,
711 we don't need the rest of the bits */
715 ON VMS process->infd holds the (event flag-1)
716 that we use for doing I/O on that process.
717 `input_wait_mask' is the cluster of event flags
720 Event flags returned start at 1 for the keyboard.
721 Since Unix expects descriptor 0 for the keyboard,
722 we substract one from the event flag.
724 inchannel
= vs
->eventFlag
-1;
726 /* Record this as an active process, with its channels.
727 As a result, child_setup will close Emacs's side of the pipes. */
728 chan_process
[inchannel
] = process
;
729 XFASTINT (XPROCESS (process
)->infd
) = inchannel
;
730 XFASTINT (XPROCESS (process
)->outfd
) = outchannel
;
731 XPROCESS (process
)->status
= Qrun
733 /* Delay interrupts until we have a chance to store
734 the new fork's pid in its process structure */
736 #define NO_ECHO "set term/noecho\r"
739 Send a command to the process to not echo input
741 The CMU PTY driver does not support SETMODEs.
743 write_to_vms_process (vs
, NO_ECHO
, strlen (NO_ECHO
));
745 XFASTINT (XPROCESS (process
)->pid
) = pid
;
753 Lisp_Object tail
, proc
;
754 register struct Lisp_Process
*p
;
755 int old_errno
= errno
;
758 sys$
setef (vs
->eventFlag
);
760 for (tail
= Vprocess_alist
; XSYMBOL (tail
) != XSYMBOL (Qnil
); tail
= XCONS (tail
)->cdr
)
762 proc
= XCONS (XCONS (tail
)->car
)->cdr
;
764 if (EQ (p
->childp
, Qt
) && XFASTINT (p
->pid
) == pid
)
768 if (XSYMBOL (tail
) == XSYMBOL (Qnil
))
771 p
->status
= Fcons (Qexit
, Fcons (make_number (vs
->exitStatus
), Qnil
))
776 defsubr (&Scall_process
);
785 for (vs
=procList
, i
=0; i
<MAX_EVENT_FLAGS
+1; i
++, vs
++)
793 procList
[0].busy
= 1; /* Zero is reserved */