diff options
Diffstat (limited to 'src/vmsproc.c')
-rw-r--r-- | src/vmsproc.c | 784 |
1 files changed, 0 insertions, 784 deletions
diff --git a/src/vmsproc.c b/src/vmsproc.c deleted file mode 100644 index ec9678f78a4..00000000000 --- a/src/vmsproc.c +++ /dev/null @@ -1,784 +0,0 @@ -/* Interfaces to subprocesses on VMS. - Copyright (C) 1988 Free Software Foundation, Inc. - -This file is part of GNU Emacs. - -GNU Emacs is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 1, or (at your option) -any later version. - -GNU Emacs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ - - -/* - Event flag and `select' emulation - - 0 is never used - 1 is the terminal - 23 is the timer event flag - 24-31 are reserved by VMS -*/ -#include <ssdef.h> -#include <iodef.h> -#include <dvidef.h> -#include <clidef.h> -#include "vmsproc.h" - -#define KEYBOARD_EVENT_FLAG 1 -#define TIMER_EVENT_FLAG 23 - -static VMS_PROC_STUFF procList[MAX_EVENT_FLAGS+1]; - -get_kbd_event_flag () -{ - /* - Return the first event flag for keyboard input. - */ - VMS_PROC_STUFF *vs = &procList[KEYBOARD_EVENT_FLAG]; - - vs->busy = 1; - vs->pid = 0; - return (vs->eventFlag); -} - -get_timer_event_flag () -{ - /* - Return the last event flag for use by timeouts - */ - VMS_PROC_STUFF *vs = &procList[TIMER_EVENT_FLAG]; - - vs->busy = 1; - vs->pid = 0; - return (vs->eventFlag); -} - -VMS_PROC_STUFF * -get_vms_process_stuff () -{ - /* - Return a process_stuff structure - - We use 1-23 as our event flags to simplify implementing - a VMS `select' call. - */ - int i; - VMS_PROC_STUFF *vs; - - for (i=1, vs = procList; i<MAX_EVENT_FLAGS; i++, vs++) - { - if (!vs->busy) - { - vs->busy = 1; - vs->inputChan = 0; - vs->pid = 0; - sys$clref (vs->eventFlag); - return (vs); - } - } - return ((VMS_PROC_STUFF *)0); -} - -give_back_vms_process_stuff (vs) - VMS_PROC_STUFF *vs; -{ - /* - Return an event flag to our pool - */ - vs->busy = 0; - vs->inputChan = 0; - vs->pid = 0; -} - -VMS_PROC_STUFF * -get_vms_process_pointer (pid) - int pid; -{ - /* - Given a pid, return the VMS_STUFF pointer - */ - int i; - VMS_PROC_STUFF *vs; - - /* Don't search the last one */ - for (i=0, vs=procList; i<MAX_EVENT_FLAGS; i++, vs++) - { - if (vs->busy && vs->pid == pid) - return (vs); - } - return ((VMS_PROC_STUFF *)0); -} - -start_vms_process_read (vs) - VMS_PROC_STUFF *vs; -{ - /* - Start an asynchronous read on a VMS process - We will catch up with the output sooner or later - */ - int status; - int ProcAst (); - - status = sys$qio (vs->eventFlag, vs->outputChan, IO$_READVBLK, - vs->iosb, 0, vs, - vs->inputBuffer, sizeof (vs->inputBuffer), 0, 0, 0, 0); - if (status != SS$_NORMAL) - return (0); - else - return (1); -} - -extern int waiting_for_ast; /* in sysdep.c */ -extern int timer_ef; -extern int input_ef; - -select (nDesc, rdsc, wdsc, edsc, timeOut) - int nDesc; - int *rdsc; - int *wdsc; - int *edsc; - int *timeOut; -{ - /* Emulate a select call - - We know that we only use event flags 1-23 - - timeout == 100000 & bit 0 set means wait on keyboard input until - something shows up. If timeout == 0, we just read the event - flags and return what we find. */ - - int nfds = 0; - int status; - int time[2]; - int delta = -10000000; - int zero = 0; - int timeout = *timeOut; - unsigned long mask, readMask, waitMask; - - if (rdsc) - readMask = *rdsc << 1; /* Unix mask is shifted over 1 */ - else - readMask = 0; /* Must be a wait call */ - - sys$clref (KEYBOARD_EVENT_FLAG); - sys$setast (0); /* Block interrupts */ - sys$readef (KEYBOARD_EVENT_FLAG, &mask); /* See what is set */ - mask &= readMask; /* Just examine what we need */ - if (mask == 0) - { /* Nothing set, we must wait */ - if (timeout != 0) - { /* Not just inspecting... */ - if (!(timeout == 100000 && - readMask == (1 << KEYBOARD_EVENT_FLAG))) - { - lib$emul (&timeout, &delta, &zero, time); - sys$setimr (TIMER_EVENT_FLAG, time, 0, 1); - waitMask = readMask | (1 << TIMER_EVENT_FLAG); - } - else - waitMask = readMask; - if (waitMask & (1 << KEYBOARD_EVENT_FLAG)) - { - sys$clref (KEYBOARD_EVENT_FLAG); - waiting_for_ast = 1; /* Only if reading from 0 */ - } - sys$setast (1); - sys$wflor (KEYBOARD_EVENT_FLAG, waitMask); - sys$cantim (1, 0); - sys$readef (KEYBOARD_EVENT_FLAG, &mask); - if (readMask & (1 << KEYBOARD_EVENT_FLAG)) - waiting_for_ast = 0; - } - } - sys$setast (1); - - /* - Count number of descriptors that are ready - */ - mask &= readMask; - if (rdsc) - *rdsc = (mask >> 1); /* Back to Unix format */ - for (nfds = 0; mask; mask >>= 1) - { - if (mask & 1) - nfds++; - } - return (nfds); -} - -#define MAX_BUFF 1024 - -write_to_vms_process (vs, buf, len) - VMS_PROC_STUFF *vs; - char *buf; - int len; -{ - /* - Write something to a VMS process. - - We have to map newlines to carriage returns for VMS. - */ - char ourBuff[MAX_BUFF]; - short iosb[4]; - int status; - int in, out; - - while (len > 0) - { - out = map_nl_to_cr (buf, ourBuff, len, MAX_BUFF); - status = sys$qiow (0, vs->inputChan, IO$_WRITEVBLK|IO$M_NOFORMAT, - iosb, 0, 0, ourBuff, out, 0, 0, 0, 0); - if (status != SS$_NORMAL || (status = iosb[0]) != SS$_NORMAL) - { - error ("Could not write to subprocess: %x", status); - return (0); - } - len =- out; - } - return (1); -} - -static -map_nl_to_cr (in, out, maxIn, maxOut) - char *in; - char *out; - int maxIn; - int maxOut; -{ - /* - Copy `in' to `out' remapping `\n' to `\r' - */ - int c; - int o; - - for (o=0; maxIn-- > 0 && o < maxOut; o++) - { - c = *in++; - *out++ = (c == '\n') ? '\r' : c; - } - return (o); -} - -clean_vms_buffer (buf, len) - char *buf; - int len; -{ - /* - Sanitize output from a VMS subprocess - Strip CR's and NULLs - */ - char *oBuf = buf; - char c; - int l = 0; - - while (len-- > 0) - { - c = *buf++; - if (c == '\r' || c == '\0') - ; - else - { - *oBuf++ = c; - l++; - } - } - return (l); -} - -/* - For the CMU PTY driver -*/ -#define PTYNAME "PYA0:" - -get_pty_channel (inDevName, outDevName, inChannel, outChannel) - char *inDevName; - char *outDevName; - int *inChannel; - int *outChannel; -{ - int PartnerUnitNumber; - int status; - struct { - int l; - char *a; - } d; - struct { - short BufLen; - short ItemCode; - int *BufAddress; - int *ItemLength; - } g[2]; - - d.l = strlen (PTYNAME); - d.a = PTYNAME; - *inChannel = 0; /* Should be `short' on VMS */ - *outChannel = 0; - *inDevName = *outDevName = '\0'; - status = sys$assign (&d, inChannel, 0, 0); - if (status == SS$_NORMAL) - { - *outChannel = *inChannel; - g[0].BufLen = sizeof (PartnerUnitNumber); - g[0].ItemCode = DVI$_UNIT; - g[0].BufAddress = &PartnerUnitNumber; - g[0].ItemLength = (int *)0; - g[1].BufLen = g[1].ItemCode = 0; - status = sys$getdviw (0, *inChannel, 0, &g, 0, 0, 0, 0); - if (status == SS$_NORMAL) - { - sprintf (inDevName, "_TPA%d:", PartnerUnitNumber); - strcpy (outDevName, inDevName); - } - } - return (status); -} - -VMSgetwd (buf) - char *buf; -{ - /* - Return the current directory - */ - char curdir[256]; - char *getenv (); - char *s; - short len; - int status; - struct - { - int l; - char *a; - } d; - - s = getenv ("SYS$DISK"); - if (s) - strcpy (buf, s); - else - *buf = '\0'; - - d.l = 255; - d.a = curdir; - status = sys$setddir (0, &len, &d); - if (status & 1) - { - curdir[len] = '\0'; - strcat (buf, curdir); - } -} - -static -call_process_ast (vs) - VMS_PROC_STUFF *vs; -{ - sys$setef (vs->eventFlag); -} - -void -child_setup (in, out, err, new_argv, env) - int in, out, err; - register char **new_argv; - char **env; -{ - /* ??? I suspect that maybe this shouldn't be done on VMS. */ -#ifdef subprocesses - /* Close Emacs's descriptors that this process should not have. */ - close_process_descs (); -#endif - - if (XTYPE (current_buffer->directory) == Lisp_String) - chdir (XSTRING (current_buffer->directory)->data); -} - -DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0, - "Call PROGRAM synchronously in a separate process.\n\ -Program's input comes from file INFILE (nil means null device, `NLA0:').\n\ -Insert output in BUFFER before point; t means current buffer;\n\ - nil for BUFFER means discard it; 0 means discard and don't wait.\n\ -Fourth arg DISPLAY non-nil means redisplay buffer as output is inserted.\n\ -Remaining arguments are strings passed as command arguments to PROGRAM.\n\ -This function waits for PROGRAM to terminate, unless BUFFER is 0;\n\ -if you quit, the process is killed.") - (nargs, args) - int nargs; - register Lisp_Object *args; -{ - Lisp_Object display, buffer, path; - char oldDir[512]; - int inchannel, outchannel; - int len; - int call_process_ast (); - struct - { - int l; - char *a; - } dcmd, din, dout; - char inDevName[65]; - char outDevName[65]; - short iosb[4]; - int status; - int SpawnFlags = CLI$M_NOWAIT; - VMS_PROC_STUFF *vs; - VMS_PROC_STUFF *get_vms_process_stuff (); - int fd[2]; - int filefd; - register int pid; - char buf[1024]; - int count = specpdl_ptr - specpdl; - register unsigned char **new_argv; - struct buffer *old = current_buffer; - - CHECK_STRING (args[0], 0); - - if (nargs <= 1 || NULL (args[1])) - args[1] = build_string ("NLA0:"); - else - args[1] = Fexpand_file_name (args[1], current_buffer->directory); - - CHECK_STRING (args[1], 1); - - { - register Lisp_Object tem; - buffer = tem = args[2]; - if (nargs <= 2) - buffer = Qnil; - else if (!(EQ (tem, Qnil) || EQ (tem, Qt) - || XFASTINT (tem) == 0)) - { - buffer = Fget_buffer (tem); - CHECK_BUFFER (buffer, 2); - } - } - - display = nargs >= 3 ? args[3] : Qnil; - - { - /* - if (args[0] == "*dcl*" then we need to skip pas the "-c", - else args[0] is the program to run. - */ - register int i; - int arg0; - int firstArg; - - if (strcmp (XSTRING (args[0])->data, "*dcl*") == 0) - { - arg0 = 5; - firstArg = 6; - } - else - { - arg0 = 0; - firstArg = 4; - } - len = XSTRING (args[arg0])->size + 1; - for (i = firstArg; i < nargs; i++) - { - CHECK_STRING (args[i], i); - len += XSTRING (args[i])->size + 1; - } - new_argv = alloca (len); - strcpy (new_argv, XSTRING (args[arg0])->data); - for (i = firstArg; i < nargs; i++) - { - strcat (new_argv, " "); - strcat (new_argv, XSTRING (args[i])->data); - } - dcmd.l = len-1; - dcmd.a = new_argv; - - status = get_pty_channel (inDevName, outDevName, &inchannel, &outchannel); - if (!(status & 1)) - error ("Error getting PTY channel: %x", status); - if (XTYPE (buffer) == Lisp_Int) - { - dout.l = strlen ("NLA0:"); - dout.a = "NLA0:"; - } - else - { - dout.l = strlen (outDevName); - dout.a = outDevName; - } - - vs = get_vms_process_stuff (); - if (!vs) - { - sys$dassgn (inchannel); - sys$dassgn (outchannel); - error ("Too many VMS processes"); - } - vs->inputChan = inchannel; - vs->outputChan = outchannel; - } - - filefd = open (XSTRING (args[1])->data, O_RDONLY, 0); - if (filefd < 0) - { - sys$dassgn (inchannel); - sys$dassgn (outchannel); - give_back_vms_process_stuff (vs); - report_file_error ("Opening process input file", Fcons (args[1], Qnil)); - } - else - close (filefd); - - din.l = XSTRING (args[1])->size; - din.a = XSTRING (args[1])->data; - - /* - Start a read on the process channel - */ - if (XTYPE (buffer) != Lisp_Int) - { - start_vms_process_read (vs); - SpawnFlags = CLI$M_NOWAIT; - } - else - SpawnFlags = 0; - - /* - On VMS we need to change the current directory - of the parent process before forking so that - the child inherit that directory. We remember - where we were before changing. - */ - VMSgetwd (oldDir); - child_setup (0, 0, 0, 0, 0); - status = lib$spawn (&dcmd, &din, &dout, &SpawnFlags, 0, &vs->pid, - &vs->exitStatus, 0, call_process_ast, vs); - chdir (oldDir); - - if (status != SS$_NORMAL) - { - sys$dassgn (inchannel); - sys$dassgn (outchannel); - give_back_vms_process_stuff (vs); - error ("Error calling LIB$SPAWN: %x", status); - } - pid = vs->pid; - - if (XTYPE (buffer) == Lisp_Int) - { -#ifndef subprocesses - wait_without_blocking (); -#endif subprocesses - return Qnil; - } - - record_unwind_protect (call_process_cleanup, - Fcons (make_number (fd[0]), make_number (pid))); - - - if (XTYPE (buffer) == Lisp_Buffer) - Fset_buffer (buffer); - - immediate_quit = 1; - QUIT; - - while (1) - { - sys$waitfr (vs->eventFlag); - if (vs->iosb[0] & 1) - { - immediate_quit = 0; - if (!NULL (buffer)) - { - vs->iosb[1] = clean_vms_buffer (vs->inputBuffer, vs->iosb[1]); - InsCStr (vs->inputBuffer, vs->iosb[1]); - } - if (!NULL (display) && INTERACTIVE) - redisplay_preserve_echo_area (); - immediate_quit = 1; - QUIT; - if (!start_vms_process_read (vs)) - break; /* The other side went away */ - } - else - break; - } - sys$dassgn (inchannel); - sys$dassgn (outchannel); - give_back_vms_process_stuff (vs); - - /* Wait for it to terminate, unless it already has. */ - wait_for_termination (pid); - - immediate_quit = 0; - - set_current_buffer (old); - - return unbind_to (count, Qnil); -} - -create_process (process, new_argv) - Lisp_Object process; - char *new_argv; -{ - int pid, inchannel, outchannel, forkin, forkout; - char old_dir[512]; - char in_dev_name[65]; - char out_dev_name[65]; - short iosb[4]; - int status; - int spawn_flags = CLI$M_NOWAIT; - int child_sig (); - struct { - int l; - char *a; - } din, dout, dprompt, dcmd; - VMS_PROC_STUFF *vs; - VMS_PROC_STUFF *get_vms_process_stuff (); - - status = get_pty_channel (in_dev_name, out_dev_name, &inchannel, &outchannel); - if (!(status & 1)) - { - remove_process (process); - error ("Error getting PTY channel: %x", status); - } - dout.l = strlen (out_dev_name); - dout.a = out_dev_name; - dprompt.l = strlen (DCL_PROMPT); - dprompt.a = DCL_PROMPT; - - if (strcmp (new_argv, "*dcl*") == 0) - { - din.l = strlen (in_dev_name); - din.a = in_dev_name; - dcmd.l = 0; - dcmd.a = (char *)0; - } - else - { - din.l = strlen ("NLA0:"); - din.a = "NLA0:"; - dcmd.l = strlen (new_argv); - dcmd.a = new_argv; - } - - /* Delay interrupts until we have a chance to store - the new fork's pid in its process structure */ - sys$setast (0); - - vs = get_vms_process_stuff (); - if (vs == 0) - { - sys$setast (1); - remove_process (process); - error ("Too many VMS processes"); - } - vs->inputChan = inchannel; - vs->outputChan = outchannel; - - /* Start a read on the process channel */ - start_vms_process_read (vs); - - /* Switch current directory so that the child inherits it. */ - VMSgetwd (old_dir); - child_setup (0, 0, 0, 0, 0); - - status = lib$spawn (&dcmd, &din, &dout, &spawn_flags, 0, &vs->pid, - &vs->exitStatus, 0, child_sig, vs, &dprompt); - chdir (old_dir); - - if (status != SS$_NORMAL) - { - sys$setast (1); - remove_process (process); - error ("Error calling LIB$SPAWN: %x", status); - } - vs->pid &= 0xffff; /* It needs to fit in a FASTINT, - we don't need the rest of the bits */ - pid = vs->pid; - - /* - ON VMS process->infd holds the (event flag-1) - that we use for doing I/O on that process. - `input_wait_mask' is the cluster of event flags - we can wait on. - - Event flags returned start at 1 for the keyboard. - Since Unix expects descriptor 0 for the keyboard, - we substract one from the event flag. - */ - inchannel = vs->eventFlag-1; - - /* Record this as an active process, with its channels. - As a result, child_setup will close Emacs's side of the pipes. */ - chan_process[inchannel] = process; - XFASTINT (XPROCESS (process)->infd) = inchannel; - XFASTINT (XPROCESS (process)->outfd) = outchannel; - XFASTINT (XPROCESS (process)->flags) = RUNNING; - - /* Delay interrupts until we have a chance to store - the new fork's pid in its process structure */ - -#define NO_ECHO "set term/noecho\r" - sys$setast (0); - /* - Send a command to the process to not echo input - - The CMU PTY driver does not support SETMODEs. - */ - write_to_vms_process (vs, NO_ECHO, strlen (NO_ECHO)); - - XFASTINT (XPROCESS (process)->pid) = pid; - sys$setast (1); -} - -child_sig (vs) - VMS_PROC_STUFF *vs; -{ - register int pid; - Lisp_Object tail, proc; - register struct Lisp_Process *p; - int old_errno = errno; - - pid = vs->pid; - sys$setef (vs->eventFlag); - - for (tail = Vprocess_alist; XSYMBOL (tail) != XSYMBOL (Qnil); tail = XCONS (tail)->cdr) - { - proc = XCONS (XCONS (tail)->car)->cdr; - p = XPROCESS (proc); - if (EQ (p->childp, Qt) && XFASTINT (p->pid) == pid) - break; - } - - if (XSYMBOL (tail) == XSYMBOL (Qnil)) - return; - - child_changed++; - XFASTINT (p->flags) = EXITED | CHANGED; - /* Truncate the exit status to 24 bits so that it fits in a FASTINT */ - XFASTINT (p->reason) = (vs->exitStatus) & 0xffffff; -} - -syms_of_vmsproc () -{ - defsubr (&Scall_process); -} - -init_vmsproc () -{ - char *malloc (); - int i; - VMS_PROC_STUFF *vs; - - for (vs=procList, i=0; i<MAX_EVENT_FLAGS+1; i++, vs++) - { - vs->busy = 0; - vs->eventFlag = i; - sys$clref (i); - vs->inputChan = 0; - vs->pid = 0; - } - procList[0].busy = 1; /* Zero is reserved */ -} |