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 2, 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, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
23 Event flag and `select' emulation
27 23 is the timer event flag
28 24-31 are reserved by VMS
42 extern Lisp_Object
call_process_cleanup ();
45 #define KEYBOARD_EVENT_FLAG 1
46 #define TIMER_EVENT_FLAG 23
48 static VMS_PROC_STUFF procList
[MAX_EVENT_FLAGS
+1];
53 Return the first event flag for keyboard input.
55 VMS_PROC_STUFF
*vs
= &procList
[KEYBOARD_EVENT_FLAG
];
59 return (vs
->eventFlag
);
62 get_timer_event_flag ()
65 Return the last event flag for use by timeouts
67 VMS_PROC_STUFF
*vs
= &procList
[TIMER_EVENT_FLAG
];
71 return (vs
->eventFlag
);
75 get_vms_process_stuff ()
78 Return a process_stuff structure
80 We use 1-23 as our event flags to simplify implementing
86 for (i
=1, vs
= procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
93 sys$
clref (vs
->eventFlag
);
97 return ((VMS_PROC_STUFF
*)0);
100 give_back_vms_process_stuff (vs
)
104 Return an event flag to our pool
112 get_vms_process_pointer (pid
)
116 Given a pid, return the VMS_STUFF pointer
121 /* Don't search the last one */
122 for (i
=0, vs
=procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
124 if (vs
->busy
&& vs
->pid
== pid
)
127 return ((VMS_PROC_STUFF
*)0);
130 start_vms_process_read (vs
)
134 Start an asynchronous read on a VMS process
135 We will catch up with the output sooner or later
140 status
= sys$
qio (vs
->eventFlag
, vs
->outputChan
, IO$_READVBLK
,
142 vs
->inputBuffer
, sizeof (vs
->inputBuffer
), 0, 0, 0, 0);
143 if (status
!= SS$_NORMAL
)
149 extern int waiting_for_ast
; /* in sysdep.c */
153 select (nDesc
, rdsc
, wdsc
, edsc
, timeOut
)
160 /* Emulate a select call
162 We know that we only use event flags 1-23
164 timeout == 100000 & bit 0 set means wait on keyboard input until
165 something shows up. If timeout == 0, we just read the event
166 flags and return what we find. */
171 int delta
= -10000000;
173 int timeout
= *timeOut
;
174 unsigned long mask
, readMask
, waitMask
;
177 readMask
= *rdsc
<< 1; /* Unix mask is shifted over 1 */
179 readMask
= 0; /* Must be a wait call */
181 sys$
clref (KEYBOARD_EVENT_FLAG
);
182 sys$
setast (0); /* Block interrupts */
183 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
); /* See what is set */
184 mask
&= readMask
; /* Just examine what we need */
186 { /* Nothing set, we must wait */
188 { /* Not just inspecting... */
189 if (!(timeout
== 100000 &&
190 readMask
== (1 << KEYBOARD_EVENT_FLAG
)))
192 lib$
emul (&timeout
, &delta
, &zero
, time
);
193 sys$
setimr (TIMER_EVENT_FLAG
, time
, 0, 1);
194 waitMask
= readMask
| (1 << TIMER_EVENT_FLAG
);
198 if (waitMask
& (1 << KEYBOARD_EVENT_FLAG
))
200 sys$
clref (KEYBOARD_EVENT_FLAG
);
201 waiting_for_ast
= 1; /* Only if reading from 0 */
204 sys$
wflor (KEYBOARD_EVENT_FLAG
, waitMask
);
206 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
);
207 if (readMask
& (1 << KEYBOARD_EVENT_FLAG
))
214 Count number of descriptors that are ready
218 *rdsc
= (mask
>> 1); /* Back to Unix format */
219 for (nfds
= 0; mask
; mask
>>= 1)
227 #define MAX_BUFF 1024
229 write_to_vms_process (vs
, buf
, len
)
235 Write something to a VMS process.
237 We have to map newlines to carriage returns for VMS.
239 char ourBuff
[MAX_BUFF
];
246 out
= map_nl_to_cr (buf
, ourBuff
, len
, MAX_BUFF
);
247 status
= sys$
qiow (0, vs
->inputChan
, IO$_WRITEVBLK
|IO$M_NOFORMAT
,
248 iosb
, 0, 0, ourBuff
, out
, 0, 0, 0, 0);
249 if (status
!= SS$_NORMAL
|| (status
= iosb
[0]) != SS$_NORMAL
)
251 error ("Could not write to subprocess: %x", status
);
260 map_nl_to_cr (in
, out
, maxIn
, maxOut
)
267 Copy `in' to `out' remapping `\n' to `\r'
272 for (o
=0; maxIn
-- > 0 && o
< maxOut
; o
++)
275 *out
++ = (c
== '\n') ? '\r' : c
;
280 clean_vms_buffer (buf
, len
)
285 Sanitize output from a VMS subprocess
295 if (c
== '\r' || c
== '\0')
307 For the CMU PTY driver
309 #define PTYNAME "PYA0:"
311 get_pty_channel (inDevName
, outDevName
, inChannel
, outChannel
)
317 int PartnerUnitNumber
;
330 d
.l
= strlen (PTYNAME
);
332 *inChannel
= 0; /* Should be `short' on VMS */
334 *inDevName
= *outDevName
= '\0';
335 status
= sys$
assign (&d
, inChannel
, 0, 0);
336 if (status
== SS$_NORMAL
)
338 *outChannel
= *inChannel
;
339 g
[0].BufLen
= sizeof (PartnerUnitNumber
);
340 g
[0].ItemCode
= DVI$_UNIT
;
341 g
[0].BufAddress
= &PartnerUnitNumber
;
342 g
[0].ItemLength
= (int *)0;
343 g
[1].BufLen
= g
[1].ItemCode
= 0;
344 status
= sys$
getdviw (0, *inChannel
, 0, &g
, 0, 0, 0, 0);
345 if (status
== SS$_NORMAL
)
347 sprintf (inDevName
, "_TPA%d:", PartnerUnitNumber
);
348 strcpy (outDevName
, inDevName
);
358 Return the current directory
371 s
= getenv ("SYS$DISK");
379 status
= sys$
setddir (0, &len
, &d
);
383 strcat (buf
, curdir
);
388 call_process_ast (vs
)
391 sys$
setef (vs
->eventFlag
);
395 child_setup (in
, out
, err
, new_argv
, env
)
397 register char **new_argv
;
400 /* ??? I suspect that maybe this shouldn't be done on VMS. */
402 /* Close Emacs's descriptors that this process should not have. */
403 close_process_descs ();
406 if (STRINGP (current_buffer
->directory
))
407 chdir (XSTRING (current_buffer
->directory
)->data
);
410 DEFUN ("call-process", Fcall_process
, Scall_process
, 1, MANY
, 0,
411 "Call PROGRAM synchronously in a separate process.\n\
412 Program's input comes from file INFILE (nil means null device, `NLA0:').\n\
413 Insert output in BUFFER before point; t means current buffer;\n\
414 nil for BUFFER means discard it; 0 means discard and don't wait.\n\
415 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\
416 Remaining arguments are strings passed as command arguments to PROGRAM.\n\
417 This function waits for PROGRAM to terminate, unless BUFFER is 0;\n\
418 if you quit, the process is killed.")
421 register Lisp_Object
*args
;
423 Lisp_Object display
, buffer
, path
;
425 int inchannel
, outchannel
;
427 int call_process_ast ();
437 int SpawnFlags
= CLI$M_NOWAIT
;
439 VMS_PROC_STUFF
*get_vms_process_stuff ();
444 int count
= specpdl_ptr
- specpdl
;
445 register unsigned char **new_argv
;
446 struct buffer
*old
= current_buffer
;
448 CHECK_STRING (args
[0], 0);
450 if (nargs
<= 1 || NILP (args
[1]))
451 args
[1] = build_string ("NLA0:");
453 args
[1] = Fexpand_file_name (args
[1], current_buffer
->directory
);
455 CHECK_STRING (args
[1], 1);
458 register Lisp_Object tem
;
459 buffer
= tem
= args
[2];
462 else if (!(EQ (tem
, Qnil
) || EQ (tem
, Qt
)
463 || XFASTINT (tem
) == 0))
465 buffer
= Fget_buffer (tem
);
466 CHECK_BUFFER (buffer
, 2);
470 display
= nargs
>= 3 ? args
[3] : Qnil
;
474 if (args[0] == "*dcl*" then we need to skip pas the "-c",
475 else args[0] is the program to run.
481 if (strcmp (XSTRING (args
[0])->data
, "*dcl*") == 0)
491 len
= XSTRING (args
[arg0
])->size
+ 1;
492 for (i
= firstArg
; i
< nargs
; i
++)
494 CHECK_STRING (args
[i
], i
);
495 len
+= XSTRING (args
[i
])->size
+ 1;
497 new_argv
= alloca (len
);
498 strcpy (new_argv
, XSTRING (args
[arg0
])->data
);
499 for (i
= firstArg
; i
< nargs
; i
++)
501 strcat (new_argv
, " ");
502 strcat (new_argv
, XSTRING (args
[i
])->data
);
507 status
= get_pty_channel (inDevName
, outDevName
, &inchannel
, &outchannel
);
509 error ("Error getting PTY channel: %x", status
);
510 if (INTEGERP (buffer
))
512 dout
.l
= strlen ("NLA0:");
517 dout
.l
= strlen (outDevName
);
521 vs
= get_vms_process_stuff ();
524 sys$
dassgn (inchannel
);
525 sys$
dassgn (outchannel
);
526 error ("Too many VMS processes");
528 vs
->inputChan
= inchannel
;
529 vs
->outputChan
= outchannel
;
532 filefd
= open (XSTRING (args
[1])->data
, O_RDONLY
, 0);
535 sys$
dassgn (inchannel
);
536 sys$
dassgn (outchannel
);
537 give_back_vms_process_stuff (vs
);
538 report_file_error ("Opening process input file", Fcons (args
[1], Qnil
));
543 din
.l
= XSTRING (args
[1])->size
;
544 din
.a
= XSTRING (args
[1])->data
;
547 Start a read on the process channel
549 if (!INTEGERP (buffer
))
551 start_vms_process_read (vs
);
552 SpawnFlags
= CLI$M_NOWAIT
;
558 On VMS we need to change the current directory
559 of the parent process before forking so that
560 the child inherit that directory. We remember
561 where we were before changing.
564 child_setup (0, 0, 0, 0, 0);
565 status
= lib$
spawn (&dcmd
, &din
, &dout
, &SpawnFlags
, 0, &vs
->pid
,
566 &vs
->exitStatus
, 0, call_process_ast
, vs
);
569 if (status
!= SS$_NORMAL
)
571 sys$
dassgn (inchannel
);
572 sys$
dassgn (outchannel
);
573 give_back_vms_process_stuff (vs
);
574 error ("Error calling LIB$SPAWN: %x", status
);
578 if (INTEGERP (buffer
))
581 wait_without_blocking ();
586 if (!NILP (display
) && INTERACTIVE
)
587 prepare_menu_bars ();
589 record_unwind_protect (call_process_cleanup
,
590 Fcons (make_number (fd
[0]), make_number (pid
)));
593 if (BUFFERP (buffer
))
594 Fset_buffer (buffer
);
601 sys$
waitfr (vs
->eventFlag
);
607 vs
->iosb
[1] = clean_vms_buffer (vs
->inputBuffer
, vs
->iosb
[1]);
608 InsCStr (vs
->inputBuffer
, vs
->iosb
[1]);
610 if (!NILP (display
) && INTERACTIVE
)
611 redisplay_preserve_echo_area ();
614 if (!start_vms_process_read (vs
))
615 break; /* The other side went away */
621 sys$
dassgn (inchannel
);
622 sys$
dassgn (outchannel
);
623 give_back_vms_process_stuff (vs
);
625 /* Wait for it to terminate, unless it already has. */
626 wait_for_termination (pid
);
630 set_current_buffer (old
);
632 return unbind_to (count
, Qnil
);
635 create_process (process
, new_argv
)
639 int pid
, inchannel
, outchannel
, forkin
, forkout
;
641 char in_dev_name
[65];
642 char out_dev_name
[65];
645 int spawn_flags
= CLI$M_NOWAIT
;
650 } din
, dout
, dprompt
, dcmd
;
652 VMS_PROC_STUFF
*get_vms_process_stuff ();
654 status
= get_pty_channel (in_dev_name
, out_dev_name
, &inchannel
, &outchannel
);
657 remove_process (process
);
658 error ("Error getting PTY channel: %x", status
);
660 dout
.l
= strlen (out_dev_name
);
661 dout
.a
= out_dev_name
;
662 dprompt
.l
= strlen (DCL_PROMPT
);
663 dprompt
.a
= DCL_PROMPT
;
665 if (strcmp (new_argv
, "*dcl*") == 0)
667 din
.l
= strlen (in_dev_name
);
674 din
.l
= strlen ("NLA0:");
676 dcmd
.l
= strlen (new_argv
);
680 /* Delay interrupts until we have a chance to store
681 the new fork's pid in its process structure */
684 vs
= get_vms_process_stuff ();
688 remove_process (process
);
689 error ("Too many VMS processes");
691 vs
->inputChan
= inchannel
;
692 vs
->outputChan
= outchannel
;
694 /* Start a read on the process channel */
695 start_vms_process_read (vs
);
697 /* Switch current directory so that the child inherits it. */
699 child_setup (0, 0, 0, 0, 0);
701 status
= lib$
spawn (&dcmd
, &din
, &dout
, &spawn_flags
, 0, &vs
->pid
,
702 &vs
->exitStatus
, 0, child_sig
, vs
, &dprompt
);
705 if (status
!= SS$_NORMAL
)
708 remove_process (process
);
709 error ("Error calling LIB$SPAWN: %x", status
);
711 vs
->pid
&= 0xffff; /* It needs to fit in a FASTINT,
712 we don't need the rest of the bits */
716 ON VMS process->infd holds the (event flag-1)
717 that we use for doing I/O on that process.
718 `input_wait_mask' is the cluster of event flags
721 Event flags returned start at 1 for the keyboard.
722 Since Unix expects descriptor 0 for the keyboard,
723 we subtract one from the event flag.
725 inchannel
= vs
->eventFlag
-1;
727 /* Record this as an active process, with its channels.
728 As a result, child_setup will close Emacs's side of the pipes. */
729 chan_process
[inchannel
] = process
;
730 XSETFASTINT (XPROCESS (process
)->infd
, inchannel
);
731 XSETFASTINT (XPROCESS (process
)->outfd
, outchannel
);
732 XPROCESS (process
)->status
= Qrun
734 /* Delay interrupts until we have a chance to store
735 the new fork's pid in its process structure */
737 #define NO_ECHO "set term/noecho\r"
740 Send a command to the process to not echo input
742 The CMU PTY driver does not support SETMODEs.
744 write_to_vms_process (vs
, NO_ECHO
, strlen (NO_ECHO
));
746 XSETFASTINT (XPROCESS (process
)->pid
, pid
);
754 Lisp_Object tail
, proc
;
755 register struct Lisp_Process
*p
;
756 int old_errno
= errno
;
759 sys$
setef (vs
->eventFlag
);
761 for (tail
= Vprocess_alist
; XSYMBOL (tail
) != XSYMBOL (Qnil
); tail
= XCONS (tail
)->cdr
)
763 proc
= XCONS (XCONS (tail
)->car
)->cdr
;
765 if (EQ (p
->childp
, Qt
) && XFASTINT (p
->pid
) == pid
)
769 if (XSYMBOL (tail
) == XSYMBOL (Qnil
))
772 p
->status
= Fcons (Qexit
, Fcons (make_number (vs
->exitStatus
), Qnil
))
777 defsubr (&Scall_process
);
786 for (vs
=procList
, i
=0; i
<MAX_EVENT_FLAGS
+1; i
++, vs
++)
794 procList
[0].busy
= 1; /* Zero is reserved */