From:	CSBVAX::MRGATE!KARNEY%PPC.MFENET@NMFECC.ARPA@SMTP  8-AUG-1988 17:04
To:	ARISIA::EVERHART
Subj:	BOSS 2.5 3/4


Received: from ppc.mfenet by ccc.mfenet with Tell via MfeNet ;
	Mon, 8 Aug 88 12:43:11 PDT
Date:	  Mon, 8 Aug 88 12:43:11 PDT
From:     KARNEY%PPC.MFENET@NMFECC.ARPA
Message-Id: <880808124311.20200218@NMFECC.ARPA>
Subject:   BOSS 2.5 3/4
To:       Everhart%Arisia.decnet@ge-crd.arpa
Comment: From KARNEY@PPC.MFENET on  8-AUG-1988 13:25:18.40 EDT

+-+-+-+ Beginning of part 3 +-+-+-+
X    execute DCL commands               in process D
X    talk to your colleague using PHONE in process P
Xand so on.
X
XAs an experimental addition, BOSS can also be run with the UW multiple-
Xwindow terminal emulator for the Macintosh.  In this case you interact with
Xthe various processes through their own windows.
X
XINSTALLATION:
X
XCompile and link with
X    $ @boss_build
XInstall with`032
X    $ @boss_install`009`009! This goes in the system startup file
X
XIn order to run BOSS, you will need pseudo TTYs installed on your system.
XContact me if you need a copy of this software.
X
XBOSS can be operated without installing it with privileges (but you will
Xstill need the pseudo TTYs installed).  If BOSS doesn't with PHY_IO
Xprivilege, then it won't be able to set the terminal type of the processes
Xunder BOSS (SHOW TERM will list the device type as UNKNOWN); the terminal
Xtype can be set with SET TERM.  If BOSS doesn't have OPER privilege, then
Xit won't be able to rebroadcast broadcast messages that it receives;
Xinstead these messages will be sent directly to the terminal.
X
XREVISION HISTORY:
X
XVersion 1.0.  August 22, 1987
XVersion 1.1.  August 27, 1987
X    Add BOSS$ID, BOSS$SWITCH, BOSS$STUFF.
XVersion 1.2.  September 30, 1987
X    Stop PHY_IO being inherited by subprocesses.
XVersion 1.3.  March 17, 1988
X  C-b buffer output
X  C-p proceed (output comes through regardless)
X  C-o suppress output (but save the last write)
X  C-s hang output
XVersion 1.4.  March 23, 1988
X  Make BOSS$SWITCH switching set output flag to s (for synchronism)
X  Default output flag is b
XVersion 1.5.  April 5, 1988
X  Fix exceeded quota problem that occurs when buflen > sysgen's maxbuf.
XVersion 1.6.  April 7, 1988
X  Fix failure to detect failure of LIB$SPAWN (e.g., when over quota).
X  Add C-t to make next process created as a top-level process.
XVersion 1.7.  June 5, 1988
X  Use separate command C-\ C-n a to create a process.
X  C-\ C-t a does this at top-level.
X  Cleaned up input routine.
XVersion 1.8.  June 7, 1988
X  Accept command line args:
X    /COMMAND_CHARACTER=char - set control character
X    /START_PROCESS=list - start up specified jobs
X    /STUFF_STRING=list - and stuff their input buffers
X    /OUTPUT_FLAGS=list - and set output flags accordingly
X    /BEGIN_PROMPT=string - part of prompt appearing before id letter
X    /END_PROMPT=string - part of prompt appearing after id letter
X    /DEFAULT_OUTPUT_FLAG=char - set default output flag
X    /SWITCH_CREATE - switching to nonexistent process creates it
XVersion 1.9.  June 8, 1988
X  Trap broadcasts to BOSS and send them on to the current process.
XVersion 2.0.  June 9, 1988
X  Add /DELETE_CHAR=char to specify a character to be interchanged with DEL.
XVersion 2.1.  June 10, 1988
X  Support selected terminal types via BOSS$TERM logical name.
XVersion 2.2.  June 26, 1988
X  Convert for new pseudo TTY drivers.
X  Change TPA to TWA; ignore SS$_DATAOVERUN; use GETDVI to get unit number
XVersion 2.3.  June 30, 1988
X  C-s (to stop output) hangs process when June 1988 PTY (TWA) drivers are used
X  with VMS 4.7.  Make BOSS try both TWA and TPA, so it works with both new
X  and old PTY drivers.
XVersion 2.4.  July 4, 1988
X  BOSS/FLOW_CONTROL to permit flow-control at BOSS level rather than
X  subprocess level.  To make this work, need to change C-s command to C-w.
XVersion 2.5.  July 22, 1988
X  Implement UW Protocol 1.  BOSS/UW.  Add /PROCESS_DEFAULT.  Add VT52 support.
X  C-k command added to kill current process.
XStill to do:
X  Make /FLOW_CONTROL work with Emacs by checking the device characteristics
X  of the pseudo TTY.  (Not sure how best to do this: Could do this with
X  setmode ast, or else check terminal setting, or else let user set a
X  per-process flag.)
X  C-l toggle output to log file sys$scratch:boss-x.log
X  C-a append to log file?
X
X*/
X
X#define VERSION`009`009"2.5"
X
X#include DESCRIP
X#include IODEF
X#include TTDEF
X#include TT2DEF
X#include JPIDEF
X#include LNMDEF
X#include PRVDEF
X#include PSLDEF
X#include SSDEF
X#include STSDEF
X#include DVIDEF
X
X#include stdio
X#include climsgdef
X
X#define  ttchrlen       12
X#define  tpdevlen       15
X#define  mbsiz          40
X#define  ttmbsiz       256
X#define  maxsiz         80
X#define  ttmaxsiz      256
X#define  imagelen       80
X#define  linesz        512
X#define  bufsize      4096`009/* Size of output buffers */
X#define  maxbuf       1200`009/* Should be less than SYSGEN MAXBUF */
X`009`009`009`009/* 1200 is in fact the minimum setting */
X#define  nprocmax        8      /* Number of process allowed */
X#define  nalphmax       26      /* Number of possible names */
X
X#define  bad(j)         !((j) & 1)
X#define  check(a)       if (bad(st = (a))) LIB$SIGNAL(st)
X
X#define NORMAL 0
X#define SWITCH 0
X#define PENDING 1
X#define CREATE 2
X#define TOP 3
X#define END 4
X#define KILL 5
X
X#define BRK$C_DEVICE      1
X#define BRK$C_USER16      47
X
X/*
X *`009uw protocol
X *
X * Copyright 1985,1986 by John D. Bruner.  All rights reserved.  Permission to
X * copy this program is given provided that the copy is not sold and that
X * this copyright notice is included.
X */
X
X#define`009P1_IAC`009`0090001`009`009/* interpret as command */
X#define`009P1_DIR`009`0090100`009`009/* command direction: */
X#define`009P1_DIR_HTOM`0090000`009`009/*`009from host to Mac */
X#define`009P1_DIR_MTOH`0090100`009`009/*`009from Mac to host */
X#define`009P1_FN`009`0090070`009`009/* function code: */
X#define`009P1_FN_NEWW`0090000`009`009/*`009new window */
X#define`009P1_FN_KILLW`0090010`009`009/*`009kill (delete) window */
X#define`009P1_FN_ISELW`0090020`009`009/*`009select window for input */
X#define`009P1_FN_OSELW`0090030`009`009/*`009select window for output */
X#define`009P1_FN_META`0090050`009`009/*`009add meta to next data char */
X#define`009P1_FN_CTLCH`0090060`009`009/*`009low 3 bits specify char */
X#define`009P1_FN_MAINT`0090070`009`009/*`009maintenance functions */
X#define`009P1_WINDOW`0090007`009`009/* window number mask */
X#define`009P1_CC`009`0090007`009`009/* control character specifier: */
X#define`009P1_CC_IAC`0091`009`009/*`009IAC */
X#define`009P1_CC_XON`0092`009`009/*`009XON */
X#define`009P1_CC_XOFF`0093`009`009/*`009XOFF */
X#define`009P1_MF`009`0090007`009`009/* maintenance functions: */
X#define`009P1_MF_ENTRY`0090`009`009/*`009beginning execution */
X#define`009P1_MF_ASKPCL`0092`009`009/*`009request protocol negotiation */
X#define`009P1_MF_CANPCL`0093`009`009/*`009suggest protocol */
X#define`009P1_MF_SETPCL`0094`009`009/*`009set current protocol */
X#define`009P1_MF_EXIT`0097`009`009/*`009execution terminating */
X#define`009P1_NWINDOW`0097`009`009/* maximum number of windows */
X
X#define UW_NORMAL 0
X#define UW_PENDING 1
X#define UW_CANPCL 2
X#define UW_SETPCL 3
X#define XON 021
X#define XOFF 023
X
Xstruct CHARBLK {
X  unsigned char class, ttype;
X  unsigned short pgwid;
X  unsigned ttchr : 24;
X  unsigned char pglen;
X  unsigned int xchar;
X};
X
Xstruct IOSBBLK {
X  unsigned short stats, tmoff, tmntr, tmsiz;
X};
X
Xtypedef struct DVIBLK {
X`009unsigned short`009len, code;
X`009char`009* buffp;
X`009long`009* lenp;
X`009long`009terminate;
X`009} DVIBLK;
X
Xint
X  py_chn[nprocmax], py_mb_chn[nprocmax], tt_chn, tt_mb_chn,
X  pid[nprocmax], st, cur, kill_proc, count[nprocmax], buflen[nprocmax],
X  procno[nalphmax], priv[2], privs[2],
X  no_phy_io, no_oper, brkthru, ctlchar, init, nproc, nalph;
X
Xstatic char
X  *clr, *bos, *ceol, *ceoln,
X  *retval, ctlchar_str[4], prompt_begin[30], prompt_end[30],
X  switch_create, flow_control, delete_char,
X  stuff_buf[256], buf[256],image[imagelen],
X  finaltp[nprocmax][tpdevlen],
X  py_mb[nprocmax][mbsiz], tt_mb[ttmbsiz],
X  input_char, tpline[nprocmax][linesz], buffer[nprocmax][bufsize],
X  term_buf[maxbuf],
X  blocked[nprocmax], mode[nprocmax], pmode[nprocmax], defmode, defproc,
X  name[nprocmax], py_post[nprocmax], proc_type[nprocmax],
X  enable_hangup[nprocmax], input_state = NORMAL, oboss_id = 0,
X  super_ac_mode = PSL$C_SUPER,
X  uw = 0, uw_state = UW_NORMAL, uw_meta = 0, first_name, last_name,
X  mac_command = 0;
X
Xextern int BOSS_CLD();
X
Xstruct CHARBLK tt_chr, tt_sav_chr;
Xstruct IOSBBLK tiosb, tiosbmb, piosb[nprocmax], miosb[nprocmax];
X
Xstatic short trnlnm_string_len;
Xstatic char trnlnm_string[81];
X
Xstruct ITEM_LST {
X`009unsigned short len, code; char *addr; short *retlen;
X  } trnlnm_item = {80, LNM$_STRING, &trnlnm_string, &trnlnm_string_len};
X
Xquit()                         /* This is done upon exiting, by exit handler */
X{
X  int i,j;
X  char id[2];
X
X  $DESCRIPTOR(d_boss_id,"BOSS$ID");
X  $DESCRIPTOR(d_id, id);
X
X  if (uw && !mac_command) uw_fun(P1_FN_MAINT | P1_MF_EXIT, 0, 0);
X
X  if (oboss_id != 0) {`009`009/* Restore BOSS$ID */
X    id[0] = oboss_id;
X    j = LIB$SET_LOGICAL(&d_boss_id,&d_id,0,0,0);
X  }
X
X  for (i = 0; i < nproc; i++) {
X    if (name[i]) {
X      j = SYS$DELMBX(py_mb_chn[i]);
X      if (bad(j))
X        printf("[SYS$DELMBX pseudo-mbx deletion failed]\n");
X    }
X  }
X  j = SYS$QIOW(0,tt_chn,IO$_SETMODE,0,0,0,&tt_sav_chr,ttchrlen,0,0,0,0);
X  if (bad(j)) printf("[SYS$QIO /setmode/ failed]\n");
X  printf("\nEnd BOSS\n");
X}
X
Xmb_srv(n)`009`009`009/* AST for mailbox message on top-level */
X`009`009`009`009/* process completion */
X     int n;
X{
X  if (proc_type[n] == TOP) {
X    if (enable_hangup[n]) comp_srv(n);
X    else {
X      enable_hangup[n] = 1;
X      check(SYS$QIO(0,py_mb_chn[n],IO$_READVBLK,&miosb[n],&mb_srv,n,
X`009`009    &py_mb[n],mbsiz,0,0,0,0));
X    }
X  }
X}
X
Xcomp_srv(n)                     /* AST for completion of processes */
X     int n;
X{
X  int j;
X
X  j = SYS$DELMBX(py_mb_chn[n]);
X  if (name[n]) procno[name[n] - first_name] = -1;
X  name[n] = '\0';
X  if (uw && !mac_command) uw_fun(P1_FN_KILLW | ((n + 1) & P1_WINDOW), 0, 0);
X  if (kill_proc == n) kill_proc = -1;
X  if (cur == n) {
X    cur = -1;
X    if (!uw) input_state = PENDING;
X  }
X}
X
Xint low_lib_spawn(n,pty_io,pid,name)
X                           /* Spawns subprocess to speaks to pseudo terminal */
Xchar *pty_io, name;
Xint  n, *pid;
X{
X  int flg = 1, len, val;
X  char proc[20],prompt[50],id[2];
X  $DESCRIPTOR(d_pty_io, pty_io); /* PTY name + number */
X  $DESCRIPTOR(d_proc, proc);   /* Process name */
X  $DESCRIPTOR(d_prompt, prompt); /* Prompt */
X  $DESCRIPTOR(d_boss_id,"BOSS$ID");
X  $DESCRIPTOR(d_id, id); /* The id */
X  d_pty_io.dsc$w_length = strlen(pty_io);
X  strcpy(proc,getenv("TT"));
X  len = strlen(proc);
X  if (proc[len-1] == ':') proc[--len] = '\0';
X  strcat(proc,"_A");
X  len = strlen(proc);
X  proc[len-1] = name;
X  d_proc.dsc$w_length= len;
X  if (proc[0] == '_') {
X    d_proc.dsc$w_length--;
X    d_proc.dsc$a_pointer++;
X  }
X  sprintf(prompt,"%s%c%s",prompt_begin,name,prompt_end);
X  d_prompt.dsc$w_length = strlen(prompt);
X  id[0] = name;
X  check(LIB$SET_LOGICAL(&d_boss_id,&d_id,0,0,0));
X  val = LIB$SPAWN(0,&d_pty_io,&d_pty_io,&flg,&d_proc,pid,0,0,
X                &comp_srv,n,&d_prompt,0);
X  check(LIB$DELETE_LOGICAL(&d_boss_id,0));
X  return(val);
X}
X
Xpy_srv(n)                       /* AST reads on pseudo terminal */
Xint n;
X{
X  int j;
X  py_post[n] = 0;
X  check(piosb[n].stats);        /* Check status */
X  count[n] = piosb[n].tmoff + piosb[n].tmsiz; /* How much was read */
X  if (n == cur || mode[n] == 'p') term_out(n);
X`009`009`009`009/* Write the stuff to the terminal */
X  else if (mode[n] == 'w') {
X    blocked[n] = 1;
X  }
X  else if (mode[n] == 'o') {
X    blocked[n] = 1;
X    check(SYS$QIO(0,py_chn[n],IO$_READVBLK,&piosb[n],&py_srv,n,
X`009`009  &tpline[n],linesz,0,0,0,0)); /* Queue next AST */
X    py_post[n] = 1;
X    }
X  else if (mode[n] == 'b') {
X    if (count[n]+buflen[n] < bufsize) {
X      for (j = 0; j < count[n]; j++) buffer[n][buflen[n]++] = tpline[n][j];
X      check(SYS$QIO(0,py_chn[n],IO$_READVBLK,&piosb[n],&py_srv,n,
X`009`009    &tpline[n],linesz,0,0,0,0)); /* Queue next AST */
X      py_post[n] = 1;
X      blocked[n] = 0;
X    }
X    else {
X      py_post[n] = 0;
X      blocked[n] = 1;
X    }
X  }
X}
X
Xto_term(buf,len,chan)
Xchar *buf;
Xint len,chan;
X{
X  int i,j;
X  char ochar;
X
X  if (!uw) {
X    j = 0;
X    while (j < len) {
X      check(SYS$QIOW(0,tt_chn,IO$_WRITEVBLK,&tiosb,0,0,&buf[j],
X`009`009     (len - j < maxbuf) ? len - j : maxbuf,
X`009`009     0,0,0,0));
X      j += maxbuf;
X    }
X  }
X  else if (chan >= 0) {
X    j = 0;
X    i = 0;
X    term_buf[i++] = P1_IAC;
X    term_buf[i++] = P1_DIR_HTOM | P1_FN_OSELW | ((chan + 1) & P1_WINDOW);
X    while (j < len) {
X      ochar = buf[j++];
X      if (ochar & 0200) {
X`009term_buf[i++] = P1_IAC;
X`009term_buf[i++] = P1_DIR_HTOM | P1_FN_META;
X`009ochar = ochar & 0177;
X      }
X      switch (ochar) {
X      case P1_IAC:
X`009term_buf[i++] = P1_IAC;
X`009term_buf[i++] = P1_DIR_HTOM | P1_FN_CTLCH | P1_CC_IAC;
X`009break;
X      case XON:
X`009term_buf[i++] = P1_IAC;
X`009term_buf[i++] = P1_DIR_HTOM | P1_FN_CTLCH | P1_CC_XON;
X`009break;
X      case XOFF:
X`009term_buf[i++] = P1_IAC;
X`009term_buf[i++] = P1_DIR_HTOM | P1_FN_CTLCH | P1_CC_XOFF;
X`009break;
X      default:
X`009term_buf[i++] = ochar;
X`009break;
X      }
X      if (i > maxbuf-4) {`009/* If no room for another meta-xon */
X`009check(SYS$QIOW(0,tt_chn,IO$_WRITEVBLK,&tiosb,0,0,term_buf,i,0,0,0,0));
X`009i = 2;`009`009`009/* Leave OSELW command in first 2 bytes */
X      }
X    }
X    if (i > 2) {`009`009/* Spit out rest of buffer */
X      check(SYS$QIOW(0,tt_chn,IO$_WRITEVBLK,&tiosb,0,0,term_buf,i,0,0,0,0));
X      i = 0;
X    }
X  }
X}
X
Xterm_out(n)
Xint n;
X{
X  int j;
X  char nname;
X  $DESCRIPTOR(d_boss_switch,"BOSS$SWITCH");
X  $DESCRIPTOR(d_boss_stuff,"BOSS$STUFF");
X  $DESCRIPTOR(d_lnm_job,"LNM$JOB");
X  if (buflen[n] > 0) {
X    to_term(buffer[n],buflen[n],n);
X    buflen[n] = 0;
X    if (blocked[n]) to_term(tpline[n],count[n],n);
X  }
X  else to_term(tpline[n],count[n],n);
X  j = SYS$TRNLNM(0,&d_lnm_job,&d_boss_switch,&super_ac_mode,&trnlnm_item);
X  if (!bad(j) && trnlnm_string_len == 1) {
X    j = LIB$DELETE_LOGICAL(&d_boss_switch,&d_lnm_job);
X    nname = toupper(trnlnm_string[0]);
X    j = SYS$TRNLNM(0,&d_lnm_job,&d_boss_stuff,&super_ac_mode,&trnlnm_item);
X    if (!bad(j)) {
X      j = LIB$DELETE_LOGICAL(&d_boss_stuff,&d_lnm_job);
X      trnlnm_string[trnlnm_string_len] = '\0';
X    } else {
X      trnlnm_string[0] = '\0';
X    }
X    if (nname >= first_name && nname <= last_name) {
X      mode[n] = 'w';
X      mov_to(nname, 0, trnlnm_string, defproc);
X    }
X  }
X  if (py_post[n] == 0) {
X    check(SYS$QIO(0,py_chn[n],IO$_READVBLK,&piosb[n],&py_srv,n,
X`009`009  &tpline[n],linesz,0,0,0,0)); /* Queue next AST */
X    py_post[n] = 1;
X    }
X  blocked[n] = 0;
X}
X
Xint count_processes()
X{
X  int j, i = 0;
X
X  for (j = 0; j < nproc; j++) if (name[j] > 0) i++;
X  return(i);
X}
X
Xdiag()
X{
X  char bufa[8];
X  int j;
X
X  if (count_processes()) {
X    sprintf(buf,"%s[Processes:",bos);
X    for (j = 0; j < nproc; j++) {
X      if (name[j] > 0) {
X        if (j == cur) sprintf(bufa," %c%c*",name[j],mode[j]);
X        else if (blocked[j]) sprintf(bufa," %c%c+",name[j],mode[j]);
X`009else if (buflen[j] > 0) sprintf(bufa," %c%c-",name[j],mode[j]);
X        else sprintf(bufa," %c%c",name[j],mode[j]);
X        strcat(buf,bufa);
X      }
X    }
X    strcat(buf,"] ");
X    strcat(buf,ceoln);
X  }
X  else sprintf(buf,"%s[No processes] %s",bos,ceoln);
X  term_msg(buf);
X}
X
Xint next_slot()
X{
X  int j = 0;
X  while ((j < nproc) && name[j]) j++;
X  return (j == nproc) ? -1 : j;
X}
X
Xterm_msg(msg)
Xchar *msg;
X{
X  to_term(msg,strlen(msg),cur);
X}
X
Xchar *get_image(pid)           /* Get the image name for a process */
X     int pid;
X{
X  int j, item;
X  short len;
X  char *ptr, *ptra;
X  $DESCRIPTOR(d_image,image);
X  ptr = &image;
X  if (pid == 0) strcpy(image,"<TOP>");
X  else {
X    item = JPI$_IMAGNAME;
X    j = LIB$GETJPI(&item,&pid,0,0,&d_image,&len);
X    if (bad(j)) strcpy(image,"<UNKNOWN>");
X    else {
X      image[len]='\0';
X      if (len == 0) {
X`009item = JPI$_CLINAME;
X`009j = LIB$GETJPI(&item,&pid,0,0,&d_image,&len);
X`009if (bad(j)) strcpy(image,"<UNKNOWN>");
X`009else image[len]='\0';
X      }
X      else {
X`009if ((ptr = strrchr(image,']'))) ptr++;
X`009else ptr = &image;
X`009if (ptra = strchr(ptr,'.')) *ptra = '\0';
X      }
X    }
X  }
X  return(ptr);
X}
X
Xint mov_to(nname, clear, string, proc_mode) /* Switch to process */
X     /* string is stuffed into input */
X     /* proc_mode says whether to create process */
Xchar nname, *string;
Xint clear,proc_mode;
X{
X  int ncur,len,j;
X  char *prefix;
X  prefix = clear ? clr : bos;
X  len = strlen(string);
X  if ((cur >= 0) && (name[cur] == nname)) { /* Redundant move */
X    mode[cur] = pmode[cur];
X    if (len == 0 & !uw) {
X      sprintf(buf,"%s[Already in process %c%c, %s]%s",
X`009      prefix,nname,mode[cur],get_image(pid[cur]),ceoln);
X      term_msg(buf);
X    }
X    j = 1;
X  }
X  else if ((ncur = procno[nname-first_name]) >= 0) { /* Existing proc */
X    cur = ncur;
X    mode[cur] = pmode[cur];
X    if (!uw) {
X      sprintf(buf,"%s[Switch to process %c%c, %s]%s",
X`009      prefix,name[cur],mode[cur],get_image(pid[cur]),ceoln);
X      term_msg(buf);
X    }
X    if (blocked[cur] || buflen[cur] > 0) term_out(cur);
X    j = 1;
X  }
X  else if (proc_mode == SWITCH) {
X    sprintf(buf,
X`009    "%s[Process %c nonexisent\007 (type %s C-n %c to create it)]%s",
X`009    bos,nname,ctlchar_str,clear ? nname : tolower(nname),ceoln);
X    term_msg(buf);
X    len = 0;
X    j = 0;
X  }
X  else if ((ncur = (uw ? (nname-first_name) : next_slot())) < 0) {
X    if (cur >= 0)
X      sprintf(buf,"%s[No process slots left--still in %c%c]%s",
X`009      bos,name[cur],mode[cur],ceoln);
X    else sprintf(buf,"%s[No process slots left]%s",bos,ceoln);
X    term_msg(buf);
X    len = 0;
X    j = 0;
X  }
X  else {
X    if (!uw) {
X      if (proc_mode == CREATE)
X`009sprintf(buf,"%s[Starting subprocess %c...%s",prefix,nname,ceol);
X      else if (proc_mode == TOP)
X`009sprintf(buf,"%s[Starting top-level process %c...%s",prefix,nname,ceol);
X      term_msg(buf);
X    }
X    j = fire_up(ncur,nname,proc_mode);
X    if (bad(j)) {
X      if (!uw) {
X`009if (cur >= 0)
X`009  sprintf(buf,"failed!!\007--still in %c%c]%s",
X`009`009  name[cur],mode[cur],ceoln);
X`009else
X`009  sprintf(buf,"failed!!\007]%s",ceoln);
X      }
X      else {
X`009sprintf(buf,"%s[Couldn't start start process %c]%s",
X`009`009prefix,nname,ceoln);
X`009uw_fun(P1_FN_KILLW | ((ncur + 1) & P1_WINDOW), 0, 0);
X      }
X      term_msg(buf);
X      len = 0;
X    } else {
X      if (!uw) {
X`009sprintf(buf,"done; now in process %c%c, %s]%s\r",
X`009`009nname,mode[ncur],get_image(pid[ncur]),ceol);
X`009term_msg(buf);
X      }
X      cur = ncur;
X      if (blocked[cur]) term_out(cur);
X    }
X  }
X/*if (j && uw && !mac_command)
X    uw_fun(P1_FN_ISELW | ((cur + 1) & P1_WINDOW), 0, 0); */
X  if (len > 0) {
X    check(SYS$QIOW(0,py_chn[cur],IO$_WRITEVBLK,&tiosb,0,0,
X                   string,len,0,0,0,0));
X    if (tiosb.stats != SS$_DATAOVERUN) check(tiosb.stats);
X  }
X  return(j);
X}
X
Xprint_help()
X{
X  if (ctlchar >= 0 && ctlchar < 040)
X    sprintf(buf,"%sBOSS commands are preceded by %s (control-%c).  \
XThe commands are:%s",bos,ctlchar_str,tolower(ctlchar+0100),ceoln);
X  else
X    sprintf(buf,"%sBOSS commands are preceded by %s.  \
XThe commands are:%s",bos,ctlchar_str,ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-h     This message%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-z     Quit%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,
X`009  "\r    %c       Switch to process %c (similarly for %c thru %c)%s",
X`009  tolower(first_name),first_name,
X`009  tolower(first_name),tolower(last_name),ceoln);
X    term_msg(buf);
X  if (!uw) {
X    sprintf(buf,"\r    %c       Clear screen and switch to process %c%s",
X`009    tolower(first_name),first_name,ceoln);
X    term_msg(buf);
X  }
X  sprintf(buf,"\r    C-n %c   Create new process %c as a subprocess%s",
X`009  tolower(first_name),first_name,ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-t %c   Create process %c at top level%s",
X`009    tolower(first_name),first_name,ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-k     Kill current process%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    ?       List processes (* means current, \
X+/- means waiting for output)%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-b     Buffer output for this process%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-o     Discard output for this process%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-p     Print output from this process%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    C-w     Stop output from this process%s",ceoln);
X  term_msg(buf);
X  sprintf(buf,"\r    %-3s     Send command character to current process%s",
X`009  ctlchar_str,ceoln);
X  term_msg(buf);
X  sprintf(buf,"\rType HELP BOSS for more information.%s",ceoln);
X  term_msg(buf);
X}
X
Xtt_srv()                        /* AST: Read on real terminal */
X{
X  int i;
X  char nname, nmode, *desc, dismiss, function, arg;
X
X  check(tiosb.stats);
X
X`009`009`009`009/* do UW decoding at first */
X  dismiss = 0;
X  if (uw) {
X    mac_command = 1;
X    switch (uw_state) {
X    case UW_NORMAL:
X      if (input_char == P1_IAC) {
X`009uw_state = UW_PENDING;
X`009dismiss = 1;
X      }
X      break;
X    case UW_PENDING:
X      uw_state = UW_NORMAL;
X      dismiss = 1;
X      if ((input_char & P1_DIR) == P1_DIR_MTOH) {
X`009function = input_char & P1_FN;
X`009arg = input_char & P1_WINDOW;
X`009switch (function) {
X`009case P1_FN_NEWW:
X`009  mov_to(first_name + (arg-1),0,"",defproc);
X`009  break;
X`009case P1_FN_KILLW:
X`009  if (name[arg-1] > 0) st = SYS$DELPRC(&pid[arg-1],0);
X`009  break;
X`009case P1_FN_ISELW:
X`009  mov_to(first_name + (arg-1),0,"",defproc);
-+-+-+-+-+ End of part 3 +-+-+-+-+-

CC:
        hydrovax%nmt@relay.cs.net
        BUHLE@XRT.UPENN.EDU
        UNOCC07%ZEUS.DNET@FERGVAX.UNL.EDU
        MARK%ISIS@MITVMA.MIT.EDU
        eric@geology.tn.cornell.edu
        Everhart%Arisia.decnet@ge-crd.arpa
        gkn@Sds.MFEnet
        ROBIN%CSVA.SAINET@NMFECC.ARPA
        LUNDIN@URVAX.BITNET
