1 /* Interfaces to subprocesses on VMS.
2 Copyright (C) 1988 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
35 #define KEYBOARD_EVENT_FLAG 1
36 #define TIMER_EVENT_FLAG 23
38 static VMS_PROC_STUFF procList
[MAX_EVENT_FLAGS
+1];
43 Return the first event flag for keyboard input.
45 VMS_PROC_STUFF
*vs
= &procList
[KEYBOARD_EVENT_FLAG
];
49 return (vs
->eventFlag
);
52 get_timer_event_flag ()
55 Return the last event flag for use by timeouts
57 VMS_PROC_STUFF
*vs
= &procList
[TIMER_EVENT_FLAG
];
61 return (vs
->eventFlag
);
65 get_vms_process_stuff ()
68 Return a process_stuff structure
70 We use 1-23 as our event flags to simplify implementing
76 for (i
=1, vs
= procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
83 sys$
clref (vs
->eventFlag
);
87 return ((VMS_PROC_STUFF
*)0);
90 give_back_vms_process_stuff (vs
)
94 Return an event flag to our pool
102 get_vms_process_pointer (pid
)
106 Given a pid, return the VMS_STUFF pointer
111 /* Don't search the last one */
112 for (i
=0, vs
=procList
; i
<MAX_EVENT_FLAGS
; i
++, vs
++)
114 if (vs
->busy
&& vs
->pid
== pid
)
117 return ((VMS_PROC_STUFF
*)0);
120 start_vms_process_read (vs
)
124 Start an asynchronous read on a VMS process
125 We will catch up with the output sooner or later
130 status
= sys$
qio (vs
->eventFlag
, vs
->outputChan
, IO$_READVBLK
,
132 vs
->inputBuffer
, sizeof (vs
->inputBuffer
), 0, 0, 0, 0);
133 if (status
!= SS$_NORMAL
)
139 extern int waiting_for_ast
; /* in sysdep.c */
143 select (nDesc
, rdsc
, wdsc
, edsc
, timeOut
)
150 /* Emulate a select call
152 We know that we only use event flags 1-23
154 timeout == 100000 & bit 0 set means wait on keyboard input until
155 something shows up. If timeout == 0, we just read the event
156 flags and return what we find. */
161 int delta
= -10000000;
163 int timeout
= *timeOut
;
164 unsigned long mask
, readMask
, waitMask
;
167 readMask
= *rdsc
<< 1; /* Unix mask is shifted over 1 */
169 readMask
= 0; /* Must be a wait call */
171 sys$
clref (KEYBOARD_EVENT_FLAG
);
172 sys$
setast (0); /* Block interrupts */
173 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
); /* See what is set */
174 mask
&= readMask
; /* Just examine what we need */
176 { /* Nothing set, we must wait */
178 { /* Not just inspecting... */
179 if (!(timeout
== 100000 &&
180 readMask
== (1 << KEYBOARD_EVENT_FLAG
)))
182 lib$
emul (&timeout
, &delta
, &zero
, time
);
183 sys$
setimr (TIMER_EVENT_FLAG
, time
, 0, 1);
184 waitMask
= readMask
| (1 << TIMER_EVENT_FLAG
);
188 if (waitMask
& (1 << KEYBOARD_EVENT_FLAG
))
190 sys$
clref (KEYBOARD_EVENT_FLAG
);
191 waiting_for_ast
= 1; /* Only if reading from 0 */
194 sys$
wflor (KEYBOARD_EVENT_FLAG
, waitMask
);
196 sys$
readef (KEYBOARD_EVENT_FLAG
, &mask
);
197 if (readMask
& (1 << KEYBOARD_EVENT_FLAG
))
204 Count number of descriptors that are ready
208 *rdsc
= (mask
>> 1); /* Back to Unix format */
209 for (nfds
= 0; mask
; mask
>>= 1)
217 #define MAX_BUFF 1024
219 write_to_vms_process (vs
, buf
, len
)
225 Write something to a VMS process.
227 We have to map newlines to carriage returns for VMS.
229 char ourBuff
[MAX_BUFF
];
236 out
= map_nl_to_cr (buf
, ourBuff
, len
, MAX_BUFF
);
237 status
= sys$
qiow (0, vs
->inputChan
, IO$_WRITEVBLK
|IO$M_NOFORMAT
,
238 iosb
, 0, 0, ourBuff
, out
, 0, 0, 0, 0);
239 if (status
!= SS$_NORMAL
|| (status
= iosb
[0]) != SS$_NORMAL
)
241 error ("Could not write to subprocess: %x", status
);
250 map_nl_to_cr (in
, out
, maxIn
, maxOut
)
257 Copy `in' to `out' remapping `\n' to `\r'
262 for (o
=0; maxIn
-- > 0 && o
< maxOut
; o
++)
265 *out
++ = (c
== '\n') ? '\r' : c
;
270 clean_vms_buffer (buf
, len
)
275 Sanitize output from a VMS subprocess
285 if (c
== '\r' || c
== '\0')
297 For the CMU PTY driver
299 #define PTYNAME "PYA0:"
301 get_pty_channel (inDevName
, outDevName
, inChannel
, outChannel
)
307 int PartnerUnitNumber
;
320 d
.l
= strlen (PTYNAME
);
322 *inChannel
= 0; /* Should be `short' on VMS */
324 *inDevName
= *outDevName
= '\0';
325 status
= sys$
assign (&d
, inChannel
, 0, 0);
326 if (status
== SS$_NORMAL
)
328 *outChannel
= *inChannel
;
329 g
[0].BufLen
= sizeof (PartnerUnitNumber
);
330 g
[0].ItemCode
= DVI$_UNIT
;
331 g
[0].BufAddress
= &PartnerUnitNumber
;
332 g
[0].ItemLength
= (int *)0;
333 g
[1].BufLen
= g
[1].ItemCode
= 0;
334 status
= sys$
getdviw (0, *inChannel
, 0, &g
, 0, 0, 0, 0);
335 if (status
== SS$_NORMAL
)
337 sprintf (inDevName
, "_TPA%d:", PartnerUnitNumber
);
338 strcpy (outDevName
, inDevName
);
348 Return the current directory
361 s
= getenv ("SYS$DISK");
369 status
= sys$
setddir (0, &len
, &d
);
373 strcat (buf
, curdir
);
378 call_process_ast (vs
)
381 sys$
setef (vs
->eventFlag
);
385 child_setup (in
, out
, err
, new_argv
, env
)
387 register char **new_argv
;
390 /* ??? I suspect that maybe this shouldn't be done on VMS. */
392 /* Close Emacs's descriptors that this process should not have. */
393 close_process_descs ();
396 if (XTYPE (current_buffer
->directory
) == Lisp_String
)
397 chdir (XSTRING (current_buffer
->directory
)->data
);
400 DEFUN ("call-process", Fcall_process
, Scall_process
, 1, MANY
, 0,
401 "Call PROGRAM synchronously in a separate process.\n\
402 Program's input comes from file INFILE (nil means null device, `NLA0:').\n\
403 Insert output in BUFFER before point; t means current buffer;\n\
404 nil for BUFFER means discard it; 0 means discard and don't wait.\n\
405 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\
406 Remaining arguments are strings passed as command arguments to PROGRAM.\n\
407 This function waits for PROGRAM to terminate, unless BUFFER is 0;\n\
408 if you quit, the process is killed.")
411 register Lisp_Object
*args
;
413 Lisp_Object display
, buffer
, path
;
415 int inchannel
, outchannel
;
417 int call_process_ast ();
427 int SpawnFlags
= CLI$M_NOWAIT
;
429 VMS_PROC_STUFF
*get_vms_process_stuff ();
434 int count
= specpdl_ptr
- specpdl
;
435 register unsigned char **new_argv
;
436 struct buffer
*old
= current_buffer
;
438 CHECK_STRING (args
[0], 0);
440 if (nargs
<= 1 || NILP (args
[1]))
441 args
[1] = build_string ("NLA0:");
443 args
[1] = Fexpand_file_name (args
[1], current_buffer
->directory
);
445 CHECK_STRING (args
[1], 1);
448 register Lisp_Object tem
;
449 buffer
= tem
= args
[2];
452 else if (!(EQ (tem
, Qnil
) || EQ (tem
, Qt
)
453 || XFASTINT (tem
) == 0))
455 buffer
= Fget_buffer (tem
);
456 CHECK_BUFFER (buffer
, 2);
460 display
= nargs
>= 3 ? args
[3] : Qnil
;
464 if (args[0] == "*dcl*" then we need to skip pas the "-c",
465 else args[0] is the program to run.
471 if (strcmp (XSTRING (args
[0])->data
, "*dcl*") == 0)
481 len
= XSTRING (args
[arg0
])->size
+ 1;
482 for (i
= firstArg
; i
< nargs
; i
++)
484 CHECK_STRING (args
[i
], i
);
485 len
+= XSTRING (args
[i
])->size
+ 1;
487 new_argv
= alloca (len
);
488 strcpy (new_argv
, XSTRING (args
[arg0
])->data
);
489 for (i
= firstArg
; i
< nargs
; i
++)
491 strcat (new_argv
, " ");
492 strcat (new_argv
, XSTRING (args
[i
])->data
);
497 status
= get_pty_channel (inDevName
, outDevName
, &inchannel
, &outchannel
);
499 error ("Error getting PTY channel: %x", status
);
500 if (XTYPE (buffer
) == Lisp_Int
)
502 dout
.l
= strlen ("NLA0:");
507 dout
.l
= strlen (outDevName
);
511 vs
= get_vms_process_stuff ();
514 sys$
dassgn (inchannel
);
515 sys$
dassgn (outchannel
);
516 error ("Too many VMS processes");
518 vs
->inputChan
= inchannel
;
519 vs
->outputChan
= outchannel
;
522 filefd
= open (XSTRING (args
[1])->data
, O_RDONLY
, 0);
525 sys$
dassgn (inchannel
);
526 sys$
dassgn (outchannel
);
527 give_back_vms_process_stuff (vs
);
528 report_file_error ("Opening process input file", Fcons (args
[1], Qnil
));
533 din
.l
= XSTRING (args
[1])->size
;
534 din
.a
= XSTRING (args
[1])->data
;
537 Start a read on the process channel
539 if (XTYPE (buffer
) != Lisp_Int
)
541 start_vms_process_read (vs
);
542 SpawnFlags
= CLI$M_NOWAIT
;
548 On VMS we need to change the current directory
549 of the parent process before forking so that
550 the child inherit that directory. We remember
551 where we were before changing.
554 child_setup (0, 0, 0, 0, 0);
555 status
= lib$
spawn (&dcmd
, &din
, &dout
, &SpawnFlags
, 0, &vs
->pid
,
556 &vs
->exitStatus
, 0, call_process_ast
, vs
);
559 if (status
!= SS$_NORMAL
)
561 sys$
dassgn (inchannel
);
562 sys$
dassgn (outchannel
);
563 give_back_vms_process_stuff (vs
);
564 error ("Error calling LIB$SPAWN: %x", status
);
568 if (XTYPE (buffer
) == Lisp_Int
)
571 wait_without_blocking ();
576 if (!NILP (display
) && INTERACTIVE
)
577 prepare_menu_bars ();
579 record_unwind_protect (call_process_cleanup
,
580 Fcons (make_number (fd
[0]), make_number (pid
)));
583 if (XTYPE (buffer
) == Lisp_Buffer
)
584 Fset_buffer (buffer
);
591 sys$
waitfr (vs
->eventFlag
);
597 vs
->iosb
[1] = clean_vms_buffer (vs
->inputBuffer
, vs
->iosb
[1]);
598 InsCStr (vs
->inputBuffer
, vs
->iosb
[1]);
600 if (!NILP (display
) && INTERACTIVE
)
601 redisplay_preserve_echo_area ();
604 if (!start_vms_process_read (vs
))
605 break; /* The other side went away */
611 sys$
dassgn (inchannel
);
612 sys$
dassgn (outchannel
);
613 give_back_vms_process_stuff (vs
);
615 /* Wait for it to terminate, unless it already has. */
616 wait_for_termination (pid
);
620 set_current_buffer (old
);
622 return unbind_to (count
, Qnil
);
625 create_process (process
, new_argv
)
629 int pid
, inchannel
, outchannel
, forkin
, forkout
;
631 char in_dev_name
[65];
632 char out_dev_name
[65];
635 int spawn_flags
= CLI$M_NOWAIT
;
640 } din
, dout
, dprompt
, dcmd
;
642 VMS_PROC_STUFF
*get_vms_process_stuff ();
644 status
= get_pty_channel (in_dev_name
, out_dev_name
, &inchannel
, &outchannel
);
647 remove_process (process
);
648 error ("Error getting PTY channel: %x", status
);
650 dout
.l
= strlen (out_dev_name
);
651 dout
.a
= out_dev_name
;
652 dprompt
.l
= strlen (DCL_PROMPT
);
653 dprompt
.a
= DCL_PROMPT
;
655 if (strcmp (new_argv
, "*dcl*") == 0)
657 din
.l
= strlen (in_dev_name
);
664 din
.l
= strlen ("NLA0:");
666 dcmd
.l
= strlen (new_argv
);
670 /* Delay interrupts until we have a chance to store
671 the new fork's pid in its process structure */
674 vs
= get_vms_process_stuff ();
678 remove_process (process
);
679 error ("Too many VMS processes");
681 vs
->inputChan
= inchannel
;
682 vs
->outputChan
= outchannel
;
684 /* Start a read on the process channel */
685 start_vms_process_read (vs
);
687 /* Switch current directory so that the child inherits it. */
689 child_setup (0, 0, 0, 0, 0);
691 status
= lib$
spawn (&dcmd
, &din
, &dout
, &spawn_flags
, 0, &vs
->pid
,
692 &vs
->exitStatus
, 0, child_sig
, vs
, &dprompt
);
695 if (status
!= SS$_NORMAL
)
698 remove_process (process
);
699 error ("Error calling LIB$SPAWN: %x", status
);
701 vs
->pid
&= 0xffff; /* It needs to fit in a FASTINT,
702 we don't need the rest of the bits */
706 ON VMS process->infd holds the (event flag-1)
707 that we use for doing I/O on that process.
708 `input_wait_mask' is the cluster of event flags
711 Event flags returned start at 1 for the keyboard.
712 Since Unix expects descriptor 0 for the keyboard,
713 we substract one from the event flag.
715 inchannel
= vs
->eventFlag
-1;
717 /* Record this as an active process, with its channels.
718 As a result, child_setup will close Emacs's side of the pipes. */
719 chan_process
[inchannel
] = process
;
720 XFASTINT (XPROCESS (process
)->infd
) = inchannel
;
721 XFASTINT (XPROCESS (process
)->outfd
) = outchannel
;
722 XFASTINT (XPROCESS (process
)->flags
) = RUNNING
;
724 /* Delay interrupts until we have a chance to store
725 the new fork's pid in its process structure */
727 #define NO_ECHO "set term/noecho\r"
730 Send a command to the process to not echo input
732 The CMU PTY driver does not support SETMODEs.
734 write_to_vms_process (vs
, NO_ECHO
, strlen (NO_ECHO
));
736 XFASTINT (XPROCESS (process
)->pid
) = pid
;
744 Lisp_Object tail
, proc
;
745 register struct Lisp_Process
*p
;
746 int old_errno
= errno
;
749 sys$
setef (vs
->eventFlag
);
751 for (tail
= Vprocess_alist
; XSYMBOL (tail
) != XSYMBOL (Qnil
); tail
= XCONS (tail
)->cdr
)
753 proc
= XCONS (XCONS (tail
)->car
)->cdr
;
755 if (EQ (p
->childp
, Qt
) && XFASTINT (p
->pid
) == pid
)
759 if (XSYMBOL (tail
) == XSYMBOL (Qnil
))
763 XFASTINT (p
->flags
) = EXITED
| CHANGED
;
764 /* Truncate the exit status to 24 bits so that it fits in a FASTINT */
765 XFASTINT (p
->reason
) = (vs
->exitStatus
) & 0xffffff;
770 defsubr (&Scall_process
);
779 for (vs
=procList
, i
=0; i
<MAX_EVENT_FLAGS
+1; i
++, vs
++)
787 procList
[0].busy
= 1; /* Zero is reserved */