Mercurial > hg > xemacs-beta
comparison src/vmsproc.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* Interfaces to subprocesses on VMS. | |
2 Copyright (C) 1988 Free Software Foundation, Inc. | |
3 | |
4 This file is part of XEmacs. | |
5 | |
6 XEmacs is free software; you can redistribute it and/or modify it | |
7 under the terms of the GNU General Public License as published by the | |
8 Free Software Foundation; either version 2, or (at your option) any | |
9 later version. | |
10 | |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
17 along with XEmacs; 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. */ | |
20 | |
21 /* Synched up with: Not synched with FSF. */ | |
22 | |
23 | |
24 /* | |
25 Event flag and `select' emulation | |
26 | |
27 0 is never used | |
28 1 is the terminal | |
29 23 is the timer event flag | |
30 24-31 are reserved by VMS | |
31 */ | |
32 #include <ssdef.h> | |
33 #include <iodef.h> | |
34 #include <dvidef.h> | |
35 #include <clidef.h> | |
36 #include "vmsproc.h" | |
37 | |
38 #define KEYBOARD_EVENT_FLAG 1 | |
39 #define TIMER_EVENT_FLAG 23 | |
40 | |
41 static VMS_PROC_STUFF procList[MAX_EVENT_FLAGS+1]; | |
42 | |
43 get_kbd_event_flag () | |
44 { | |
45 /* | |
46 Return the first event flag for keyboard input. | |
47 */ | |
48 VMS_PROC_STUFF *vs = &procList[KEYBOARD_EVENT_FLAG]; | |
49 | |
50 vs->busy = 1; | |
51 vs->pid = 0; | |
52 return (vs->eventFlag); | |
53 } | |
54 | |
55 get_timer_event_flag () | |
56 { | |
57 /* | |
58 Return the last event flag for use by timeouts | |
59 */ | |
60 VMS_PROC_STUFF *vs = &procList[TIMER_EVENT_FLAG]; | |
61 | |
62 vs->busy = 1; | |
63 vs->pid = 0; | |
64 return (vs->eventFlag); | |
65 } | |
66 | |
67 VMS_PROC_STUFF * | |
68 get_vms_process_stuff () | |
69 { | |
70 /* | |
71 Return a process_stuff structure | |
72 | |
73 We use 1-23 as our event flags to simplify implementing | |
74 a VMS `select' call. | |
75 */ | |
76 int i; | |
77 VMS_PROC_STUFF *vs; | |
78 | |
79 for (i=1, vs = procList; i<MAX_EVENT_FLAGS; i++, vs++) | |
80 { | |
81 if (!vs->busy) | |
82 { | |
83 vs->busy = 1; | |
84 vs->inputChan = 0; | |
85 vs->pid = 0; | |
86 sys$clref (vs->eventFlag); | |
87 return (vs); | |
88 } | |
89 } | |
90 return ((VMS_PROC_STUFF *)0); | |
91 } | |
92 | |
93 give_back_vms_process_stuff (vs) | |
94 VMS_PROC_STUFF *vs; | |
95 { | |
96 /* | |
97 Return an event flag to our pool | |
98 */ | |
99 vs->busy = 0; | |
100 vs->inputChan = 0; | |
101 vs->pid = 0; | |
102 } | |
103 | |
104 VMS_PROC_STUFF * | |
105 get_vms_process_pointer (pid) | |
106 int pid; | |
107 { | |
108 /* | |
109 Given a pid, return the VMS_STUFF pointer | |
110 */ | |
111 int i; | |
112 VMS_PROC_STUFF *vs; | |
113 | |
114 /* Don't search the last one */ | |
115 for (i=0, vs=procList; i<MAX_EVENT_FLAGS; i++, vs++) | |
116 { | |
117 if (vs->busy && vs->pid == pid) | |
118 return (vs); | |
119 } | |
120 return ((VMS_PROC_STUFF *)0); | |
121 } | |
122 | |
123 start_vms_process_read (vs) | |
124 VMS_PROC_STUFF *vs; | |
125 { | |
126 /* | |
127 Start an asynchronous read on a VMS process | |
128 We will catch up with the output sooner or later | |
129 */ | |
130 int status; | |
131 int ProcAst (); | |
132 | |
133 status = sys$qio (vs->eventFlag, vs->outputChan, IO$_READVBLK, | |
134 vs->iosb, 0, vs, | |
135 vs->inputBuffer, sizeof (vs->inputBuffer), 0, 0, 0, 0); | |
136 if (status != SS$_NORMAL) | |
137 return (0); | |
138 else | |
139 return (1); | |
140 } | |
141 | |
142 extern int waiting_for_ast; /* in sysdep.c */ | |
143 extern int timer_ef; | |
144 extern int input_ef; | |
145 | |
146 select (nDesc, rdsc, wdsc, edsc, timeOut) | |
147 int nDesc; | |
148 int *rdsc; | |
149 int *wdsc; | |
150 int *edsc; | |
151 int *timeOut; | |
152 { | |
153 /* Emulate a select call | |
154 | |
155 We know that we only use event flags 1-23 | |
156 | |
157 timeout == 100000 & bit 0 set means wait on keyboard input until | |
158 something shows up. If timeout == 0, we just read the event | |
159 flags and return what we find. */ | |
160 | |
161 int nfds = 0; | |
162 int status; | |
163 int time[2]; | |
164 int delta = -10000000; | |
165 int zero = 0; | |
166 int timeout = *timeOut; | |
167 unsigned long mask, readMask, waitMask; | |
168 | |
169 if (rdsc) | |
170 readMask = *rdsc << 1; /* Unix mask is shifted over 1 */ | |
171 else | |
172 readMask = 0; /* Must be a wait call */ | |
173 | |
174 sys$clref (KEYBOARD_EVENT_FLAG); | |
175 sys$setast (0); /* Block interrupts */ | |
176 sys$readef (KEYBOARD_EVENT_FLAG, &mask); /* See what is set */ | |
177 mask &= readMask; /* Just examine what we need */ | |
178 if (mask == 0) | |
179 { /* Nothing set, we must wait */ | |
180 if (timeout != 0) | |
181 { /* Not just inspecting... */ | |
182 if (!(timeout == 100000 && | |
183 readMask == (1 << KEYBOARD_EVENT_FLAG))) | |
184 { | |
185 lib$emul (&timeout, &delta, &zero, time); | |
186 sys$setimr (TIMER_EVENT_FLAG, time, 0, 1); | |
187 waitMask = readMask | (1 << TIMER_EVENT_FLAG); | |
188 } | |
189 else | |
190 waitMask = readMask; | |
191 if (waitMask & (1 << KEYBOARD_EVENT_FLAG)) | |
192 { | |
193 sys$clref (KEYBOARD_EVENT_FLAG); | |
194 waiting_for_ast = 1; /* Only if reading from 0 */ | |
195 } | |
196 sys$setast (1); | |
197 sys$wflor (KEYBOARD_EVENT_FLAG, waitMask); | |
198 sys$cantim (1, 0); | |
199 sys$readef (KEYBOARD_EVENT_FLAG, &mask); | |
200 if (readMask & (1 << KEYBOARD_EVENT_FLAG)) | |
201 waiting_for_ast = 0; | |
202 } | |
203 } | |
204 sys$setast (1); | |
205 | |
206 /* | |
207 Count number of descriptors that are ready | |
208 */ | |
209 mask &= readMask; | |
210 if (rdsc) | |
211 *rdsc = (mask >> 1); /* Back to Unix format */ | |
212 for (nfds = 0; mask; mask >>= 1) | |
213 { | |
214 if (mask & 1) | |
215 nfds++; | |
216 } | |
217 return (nfds); | |
218 } | |
219 | |
220 #define MAX_BUFF 1024 | |
221 | |
222 write_to_vms_process (vs, buf, len) | |
223 VMS_PROC_STUFF *vs; | |
224 char *buf; | |
225 int len; | |
226 { | |
227 /* | |
228 Write something to a VMS process. | |
229 | |
230 We have to map newlines to carriage returns for VMS. | |
231 */ | |
232 char ourBuff[MAX_BUFF]; | |
233 short iosb[4]; | |
234 int status; | |
235 int in, out; | |
236 | |
237 while (len > 0) | |
238 { | |
239 out = map_nl_to_cr (buf, ourBuff, len, MAX_BUFF); | |
240 status = sys$qiow (0, vs->inputChan, IO$_WRITEVBLK|IO$M_NOFORMAT, | |
241 iosb, 0, 0, ourBuff, out, 0, 0, 0, 0); | |
242 if (status != SS$_NORMAL || (status = iosb[0]) != SS$_NORMAL) | |
243 { | |
244 error ("Could not write to subprocess: %x", status); | |
245 return (0); | |
246 } | |
247 len =- out; | |
248 } | |
249 return (1); | |
250 } | |
251 | |
252 static | |
253 map_nl_to_cr (in, out, maxIn, maxOut) | |
254 char *in; | |
255 char *out; | |
256 int maxIn; | |
257 int maxOut; | |
258 { | |
259 /* | |
260 Copy `in' to `out' remapping `\n' to `\r' | |
261 */ | |
262 int c; | |
263 int o; | |
264 | |
265 for (o=0; maxIn-- > 0 && o < maxOut; o++) | |
266 { | |
267 c = *in++; | |
268 *out++ = (c == '\n') ? '\r' : c; | |
269 } | |
270 return (o); | |
271 } | |
272 | |
273 clean_vms_buffer (buf, len) | |
274 char *buf; | |
275 int len; | |
276 { | |
277 /* | |
278 Sanitize output from a VMS subprocess | |
279 Strip CR's and NULLs | |
280 */ | |
281 char *oBuf = buf; | |
282 char c; | |
283 int l = 0; | |
284 | |
285 while (len-- > 0) | |
286 { | |
287 c = *buf++; | |
288 if (c == '\r' || c == '\0') | |
289 ; | |
290 else | |
291 { | |
292 *oBuf++ = c; | |
293 l++; | |
294 } | |
295 } | |
296 return (l); | |
297 } | |
298 | |
299 /* | |
300 For the CMU PTY driver | |
301 */ | |
302 #define PTYNAME "PYA0:" | |
303 | |
304 get_pty_channel (inDevName, outDevName, inChannel, outChannel) | |
305 char *inDevName; | |
306 char *outDevName; | |
307 int *inChannel; | |
308 int *outChannel; | |
309 { | |
310 int PartnerUnitNumber; | |
311 int status; | |
312 struct { | |
313 int l; | |
314 char *a; | |
315 } d; | |
316 struct { | |
317 short BufLen; | |
318 short ItemCode; | |
319 int *BufAddress; | |
320 int *ItemLength; | |
321 } g[2]; | |
322 | |
323 d.l = strlen (PTYNAME); | |
324 d.a = PTYNAME; | |
325 *inChannel = 0; /* Should be `short' on VMS */ | |
326 *outChannel = 0; | |
327 *inDevName = *outDevName = '\0'; | |
328 status = sys$assign (&d, inChannel, 0, 0); | |
329 if (status == SS$_NORMAL) | |
330 { | |
331 *outChannel = *inChannel; | |
332 g[0].BufLen = sizeof (PartnerUnitNumber); | |
333 g[0].ItemCode = DVI$_UNIT; | |
334 g[0].BufAddress = &PartnerUnitNumber; | |
335 g[0].ItemLength = (int *)0; | |
336 g[1].BufLen = g[1].ItemCode = 0; | |
337 status = sys$getdviw (0, *inChannel, 0, &g, 0, 0, 0, 0); | |
338 if (status == SS$_NORMAL) | |
339 { | |
340 sprintf (inDevName, "_TPA%d:", PartnerUnitNumber); | |
341 strcpy (outDevName, inDevName); | |
342 } | |
343 } | |
344 return (status); | |
345 } | |
346 | |
347 VMSgetwd (buf) | |
348 char *buf; | |
349 { | |
350 /* | |
351 Return the current directory | |
352 */ | |
353 char curdir[256]; | |
354 char *getenv (); | |
355 char *s; | |
356 short len; | |
357 int status; | |
358 struct | |
359 { | |
360 int l; | |
361 char *a; | |
362 } d; | |
363 | |
364 s = getenv ("SYS$DISK"); | |
365 if (s) | |
366 strcpy (buf, s); | |
367 else | |
368 *buf = '\0'; | |
369 | |
370 d.l = 255; | |
371 d.a = curdir; | |
372 status = sys$setddir (0, &len, &d); | |
373 if (status & 1) | |
374 { | |
375 curdir[len] = '\0'; | |
376 strcat (buf, curdir); | |
377 } | |
378 } | |
379 | |
380 static | |
381 call_process_ast (vs) | |
382 VMS_PROC_STUFF *vs; | |
383 { | |
384 sys$setef (vs->eventFlag); | |
385 } | |
386 | |
387 void | |
388 child_setup (in, out, err, new_argv, env) | |
389 int in, out, err; | |
390 char **new_argv; | |
391 char **env; | |
392 { | |
393 /* ??? I suspect that maybe this shouldn't be done on VMS. */ | |
394 /* Close Emacs's descriptors that this process should not have. */ | |
395 close_process_descs (); | |
396 | |
397 if (STRINGP (current_buffer->directory)) | |
398 chdir (string_data (XSTRING (current_buffer->directory))); | |
399 } | |
400 | |
401 DEFUN ("call-process-internal", Fcall_process_internal, | |
402 Scall_process_internal, 1, MANY, 0 /* | |
403 Call PROGRAM synchronously in a separate process. | |
404 Program's input comes from file INFILE (nil means null device, `NLA0:'). | |
405 Insert output in BUFFER before point; t means current buffer; | |
406 nil for BUFFER means discard it; 0 means discard and don't wait. | |
407 Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted. | |
408 Remaining arguments are strings passed as command arguments to PROGRAM. | |
409 This function waits for PROGRAM to terminate, unless BUFFER is 0; | |
410 if you quit, the process is killed. | |
411 */ ) | |
412 (nargs, args) | |
413 int nargs; | |
414 Lisp_Object *args; | |
415 { | |
416 /* This function can GC */ | |
417 Lisp_Object display, buffer, path; | |
418 char oldDir[512]; | |
419 int inchannel, outchannel; | |
420 int len; | |
421 int call_process_ast (); | |
422 struct | |
423 { | |
424 int l; | |
425 char *a; | |
426 } dcmd, din, dout; | |
427 char inDevName[65]; | |
428 char outDevName[65]; | |
429 short iosb[4]; | |
430 int status; | |
431 int SpawnFlags = CLI$M_NOWAIT; | |
432 VMS_PROC_STUFF *vs; | |
433 VMS_PROC_STUFF *get_vms_process_stuff (); | |
434 int fd[2]; | |
435 int filefd; | |
436 int pid; | |
437 char buf[1024]; | |
438 int speccount = specpdl_depth (); | |
439 unsigned char **new_argv; | |
440 struct buffer *old = current_buffer; | |
441 | |
442 CHECK_STRING (args[0]); | |
443 | |
444 if (nargs <= 1 || NILP (args[1])) | |
445 args[1] = build_string ("NLA0:"); | |
446 else | |
447 args[1] = Fexpand_file_name (args[1], | |
448 current_buffer->directory); | |
449 | |
450 CHECK_STRING (args[1]); | |
451 | |
452 { | |
453 Lisp_Object tem; | |
454 buffer = tem = args[2]; | |
455 if (nargs <= 2) | |
456 buffer = Qnil; | |
457 else if (!(ZEROP (tem, Qnil) || EQ (tem, Qt) || EQ (tem)) | |
458 { | |
459 buffer = Fget_buffer (tem); | |
460 CHECK_BUFFER (buffer); | |
461 } | |
462 } | |
463 | |
464 display = nargs >= 3 ? args[3] : Qnil; | |
465 | |
466 { | |
467 /* | |
468 if (args[0] == "*dcl*" then we need to skip pas the "-c", | |
469 else args[0] is the program to run. | |
470 */ | |
471 int i; | |
472 int arg0; | |
473 int firstArg; | |
474 | |
475 if (strcmp (string_data (XSTRING (args[0])), "*dcl*") == 0) | |
476 { | |
477 arg0 = 5; | |
478 firstArg = 6; | |
479 } | |
480 else | |
481 { | |
482 arg0 = 0; | |
483 firstArg = 4; | |
484 } | |
485 len = string_length (XSTRING (args[arg0])) + 1; | |
486 for (i = firstArg; i < nargs; i++) | |
487 { | |
488 CHECK_STRING (args[i]); | |
489 len += string_length (XSTRING (args[i])) + 1; | |
490 } | |
491 new_argv = alloca (len); | |
492 strcpy (new_argv, string_data (XSTRING (args[arg0]))); | |
493 for (i = firstArg; i < nargs; i++) | |
494 { | |
495 strcat (new_argv, " "); | |
496 strcat (new_argv, string_data (XSTRING (args[i]))); | |
497 } | |
498 dcmd.l = len-1; | |
499 dcmd.a = new_argv; | |
500 | |
501 status = get_pty_channel (inDevName, outDevName, &inchannel, &outchannel); | |
502 if (!(status & 1)) | |
503 error ("Error getting PTY channel: %x", status); | |
504 if (INTP (buffer)) | |
505 { | |
506 dout.l = strlen ("NLA0:"); | |
507 dout.a = "NLA0:"; | |
508 } | |
509 else | |
510 { | |
511 dout.l = strlen (outDevName); | |
512 dout.a = outDevName; | |
513 } | |
514 | |
515 vs = get_vms_process_stuff (); | |
516 if (!vs) | |
517 { | |
518 sys$dassgn (inchannel); | |
519 sys$dassgn (outchannel); | |
520 error ("Too many VMS processes"); | |
521 } | |
522 vs->inputChan = inchannel; | |
523 vs->outputChan = outchannel; | |
524 } | |
525 | |
526 filefd = open (string_data (XSTRING (args[1])), O_RDONLY, 0); | |
527 if (filefd < 0) | |
528 { | |
529 sys$dassgn (inchannel); | |
530 sys$dassgn (outchannel); | |
531 give_back_vms_process_stuff (vs); | |
532 report_file_error ("Opening process input file", Fcons (args[1], Qnil)); | |
533 } | |
534 else | |
535 close (filefd); | |
536 | |
537 din.l = string_length (XSTRING (args[1])); | |
538 din.a = string_data (XSTRING (args[1])); | |
539 | |
540 /* | |
541 Start a read on the process channel | |
542 */ | |
543 if (!INTP (buffer)) | |
544 { | |
545 start_vms_process_read (vs); | |
546 SpawnFlags = CLI$M_NOWAIT; | |
547 } | |
548 else | |
549 SpawnFlags = 0; | |
550 | |
551 /* | |
552 On VMS we need to change the current directory | |
553 of the parent process before forking so that | |
554 the child inherit that directory. We remember | |
555 where we were before changing. | |
556 */ | |
557 VMSgetwd (oldDir); | |
558 child_setup (0, 0, 0, 0, 0); | |
559 status = lib$spawn (&dcmd, &din, &dout, &SpawnFlags, 0, &vs->pid, | |
560 &vs->exitStatus, 0, call_process_ast, vs); | |
561 chdir (oldDir); | |
562 | |
563 if (status != SS$_NORMAL) | |
564 { | |
565 sys$dassgn (inchannel); | |
566 sys$dassgn (outchannel); | |
567 give_back_vms_process_stuff (vs); | |
568 error ("Error calling LIB$SPAWN: %x", status); | |
569 } | |
570 pid = vs->pid; | |
571 | |
572 if (INTP (buffer)) | |
573 { | |
574 #if defined (NO_SUBPROCESSES) | |
575 wait_without_blocking (); | |
576 #endif | |
577 return Qnil; | |
578 } | |
579 | |
580 record_unwind_protect (call_process_cleanup, | |
581 Fcons (make_int (fd[0]), make_int (pid))); | |
582 | |
583 | |
584 if (BUFFERP (buffer)) | |
585 Fset_buffer (buffer); | |
586 | |
587 while (1) | |
588 { | |
589 QUIT; | |
590 | |
591 sys$waitfr (vs->eventFlag); | |
592 if (vs->iosb[0] & 1) | |
593 { | |
594 if (!NILP (buffer)) | |
595 { | |
596 vs->iosb[1] = clean_vms_buffer (vs->inputBuffer, vs->iosb[1]); | |
597 InsCStr (vs->inputBuffer, vs->iosb[1]); | |
598 } | |
599 if (!NILP (display) && INTERACTIVE) | |
600 redisplay (); | |
601 QUIT; | |
602 if (!start_vms_process_read (vs)) | |
603 break; /* The other side went away */ | |
604 } | |
605 else | |
606 break; | |
607 } | |
608 sys$dassgn (inchannel); | |
609 sys$dassgn (outchannel); | |
610 give_back_vms_process_stuff (vs); | |
611 | |
612 /* Wait for it to terminate, unless it already has. */ | |
613 wait_for_termination (pid); | |
614 | |
615 set_current_buffer (old); | |
616 | |
617 return unbind_to (speccount, Qnil); | |
618 } | |
619 | |
620 create_process (process, new_argv) | |
621 Lisp_Object process; | |
622 char *new_argv; | |
623 { | |
624 int pid, inchannel, outchannel, forkin, forkout; | |
625 char old_dir[512]; | |
626 char in_dev_name[65]; | |
627 char out_dev_name[65]; | |
628 short iosb[4]; | |
629 int status; | |
630 int spawn_flags = CLI$M_NOWAIT; | |
631 int child_sig (); | |
632 struct { | |
633 int l; | |
634 char *a; | |
635 } din, dout, dprompt, dcmd; | |
636 VMS_PROC_STUFF *vs; | |
637 VMS_PROC_STUFF *get_vms_process_stuff (); | |
638 | |
639 status = get_pty_channel (in_dev_name, out_dev_name, &inchannel, &outchannel); | |
640 if (!(status & 1)) | |
641 { | |
642 remove_process (process); | |
643 error ("Error getting PTY channel: %x", status); | |
644 } | |
645 dout.l = strlen (out_dev_name); | |
646 dout.a = out_dev_name; | |
647 dprompt.l = strlen (DCL_PROMPT); | |
648 dprompt.a = DCL_PROMPT; | |
649 | |
650 if (strcmp (new_argv, "*dcl*") == 0) | |
651 { | |
652 din.l = strlen (in_dev_name); | |
653 din.a = in_dev_name; | |
654 dcmd.l = 0; | |
655 dcmd.a = (char *)0; | |
656 } | |
657 else | |
658 { | |
659 din.l = strlen ("NLA0:"); | |
660 din.a = "NLA0:"; | |
661 dcmd.l = strlen (new_argv); | |
662 dcmd.a = new_argv; | |
663 } | |
664 | |
665 /* Delay interrupts until we have a chance to store | |
666 the new fork's pid in its process structure */ | |
667 sys$setast (0); | |
668 | |
669 vs = get_vms_process_stuff (); | |
670 if (vs == 0) | |
671 { | |
672 sys$setast (1); | |
673 remove_process (process); | |
674 error ("Too many VMS processes"); | |
675 } | |
676 vs->inputChan = inchannel; | |
677 vs->outputChan = outchannel; | |
678 | |
679 /* Start a read on the process channel */ | |
680 start_vms_process_read (vs); | |
681 | |
682 /* Switch current directory so that the child inherits it. */ | |
683 VMSgetwd (old_dir); | |
684 child_setup (0, 0, 0, 0, 0); | |
685 | |
686 status = lib$spawn (&dcmd, &din, &dout, &spawn_flags, 0, &vs->pid, | |
687 &vs->exitStatus, 0, child_sig, vs, &dprompt); | |
688 chdir (old_dir); | |
689 | |
690 if (status != SS$_NORMAL) | |
691 { | |
692 sys$setast (1); | |
693 remove_process (process); | |
694 error ("Error calling LIB$SPAWN: %x", status); | |
695 } | |
696 vs->pid &= 0xffff; /* It needs to fit in a FASTINT, | |
697 we don't need the rest of the bits */ | |
698 pid = vs->pid; | |
699 | |
700 /* | |
701 ON VMS process->infd holds the (event flag-1) | |
702 that we use for doing I/O on that process. | |
703 `input_wait_mask' is the cluster of event flags | |
704 we can wait on. | |
705 | |
706 Event flags returned start at 1 for the keyboard. | |
707 Since Unix expects descriptor 0 for the keyboard, | |
708 we substract one from the event flag. | |
709 */ | |
710 inchannel = vs->eventFlag-1; | |
711 | |
712 /* Record this as an active process, with its channels. | |
713 As a result, child_setup will close Emacs's side of the pipes. */ | |
714 chan_process[inchannel] = process; | |
715 XPROCESS (process)->infd = make_int (inchannel); | |
716 XPROCESS (process)->outfd = make_int (outchannel); | |
717 XPROCESS (process)->flags = make_int (RUNNING); | |
718 | |
719 /* Delay interrupts until we have a chance to store | |
720 the new fork's pid in its process structure */ | |
721 | |
722 #define NO_ECHO "set term/noecho\r" | |
723 sys$setast (0); | |
724 /* | |
725 Send a command to the process to not echo input | |
726 | |
727 The CMU PTY driver does not support SETMODEs. | |
728 */ | |
729 write_to_vms_process (vs, NO_ECHO, strlen (NO_ECHO)); | |
730 | |
731 XPROCESS (process)->pid = make_int (pid); | |
732 sys$setast (1); | |
733 } | |
734 | |
735 child_sig (VMS_PROC_STUFF *vs) | |
736 { | |
737 int pid; | |
738 Lisp_Object tail, proc; | |
739 struct Lisp_Process *p; | |
740 int old_errno = errno; | |
741 | |
742 pid = vs->pid; | |
743 sys$setef (vs->eventFlag); | |
744 | |
745 for (tail = Vprocess_alist; XSYMBOL (tail) != XSYMBOL (Qnil); tail = XCDR (tail)) | |
746 { | |
747 proc = XCDR (XCAR (tail)); | |
748 p = XPROCESS (proc); | |
749 if (EQ (p->childp, Qt) && XINT (p->pid) == pid) | |
750 break; | |
751 } | |
752 | |
753 if (XSYMBOL (tail) == XSYMBOL (Qnil)) | |
754 return; | |
755 | |
756 child_changed++; | |
757 p->flags = make_int (EXITED | CHANGED); | |
758 /* Truncate the exit status to 24 bits so that it fits in a FASTINT */ | |
759 p->reason = make_int ((vs->exitStatus) & 0xffffff); | |
760 } | |
761 | |
762 void | |
763 syms_of_vmsproc (void) | |
764 { | |
765 defsubr (&Scall_process_internal); | |
766 } | |
767 | |
768 void | |
769 init_vmsproc (void) | |
770 { | |
771 char *malloc (); | |
772 int i; | |
773 VMS_PROC_STUFF *vs; | |
774 | |
775 for (vs=procList, i=0; i<MAX_EVENT_FLAGS+1; i++, vs++) | |
776 { | |
777 vs->busy = 0; | |
778 vs->eventFlag = i; | |
779 sys$clref (i); | |
780 vs->inputChan = 0; | |
781 vs->pid = 0; | |
782 } | |
783 procList[0].busy = 1; /* Zero is reserved */ | |
784 } |