[comp.os.vms] BOSS interactive job controller source

KARNEY%PPC.MFENET@NMFECC.ARPA (08/25/87)

Here is a program I wrote to allow VMS users to run several interactive
jobs simultaneously.  

BOSS lets you create up to 8 processes.  One of these processes is
`current'.  This means that what you type is sent to that process, and
output from that process is sent to your terminal.  A process which is not
current can run but cannot do output.  You can make some other process
current by typing control-\ followed by an identifying letter.

BOSS requires that you have Pseudo TTYs installed.

    Charles Karney
    Plasma Physics Laboratory   Phone:   609/683-2607
    Princeton University        MFENet:  Karney@PPC.MFENET
    PO Box 451                  ARPANet: Karney%PPC.MFENET@NMFECC.ARPA
    Princeton, NJ 08544-0451    Bitnet:  Karney%PPC.MFENET@ANLVMS.BITNET

....................... Cut between dotted lines and save ......................
$!..............................................................................
$! VAX/VMS archive file created by VMS_SHAR V-4.03 05-Aug-1987
$! which was written by Michael Bednarek (U3369429@ucsvc.dn.mu.oz.au)
$! To unpack, simply save and execute (@) this file.
$!
$! This archive was created by KARNEY
$!      on Tuesday 25-AUG-1987 11:03:30.41
$!
$! ATTENTION: To keep each article below 15872 bytes, this program
$!            has been transmitted in 2 parts.
$! You should concatenate ALL parts to ONE file and execute (@) that file.
$!
$! It contains the following 2 files:
$! BOSS.HLP BOSS.C
$!==============================================================================
$ Set Symbol/Scope=(NoLocal,NoGlobal)
$ Version=F$GetSYI("VERSION") ! See what VMS version we have here:
$ If Version.ges."V4.4" then goto Version_OK
$ Write SYS$Output "Sorry, you are running VMS ",Version, -
                ", but this procedure requires V4.4 or higher."
$ Exit 44
$Version_OK: CR[0,8]=13
$ Pass_or_Failed="failed!,passed."
$ Goto Start
$Convert_File:
$ Read/Time_Out=0/Error=No_Error1/Prompt="creating ''File_is'" SYS$Command ddd
$No_Error1: Define/User_Mode SYS$Output NL:
$ Edit/TPU/NoSection/NoDisplay/Command=SYS$Input/Output='File_is' -
        VMS_SHAR_DUMMY.DUMMY
f:=Get_Info(Command_Line,"File_Name");b:=Create_Buffer("",f);
o:=Get_Info(Command_Line,"Output_File");Set (Output_File,b,o);
Position (Beginning_of(b));Loop x:=Erase_Character(1); Loop ExitIf x<>"V";
Move_Vertical(1);x:=Erase_Character(1);Append_Line;Move_Horizontal
(-Current_Offset);EndLoop;Move_Vertical(1);ExitIf Mark(None)=End_of(b)
EndLoop;Exit;
$ Delete VMS_SHAR_DUMMY.DUMMY;*
$ Checksum 'File_is
$ Success=F$Element(Check_Sum_is.eq.CHECKSUM$CHECKSUM,",",Pass_or_Failed)+CR
$ Read/Time_Out=0/Error=No_Error2/Prompt=" CHECKSUM ''Success'" SYS$Command ddd
$No_Error2: Return
$Start:
$ File_is="BOSS.HLP"
$ Check_Sum_is=1796768615
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X1 BOSS
XBOSS is an interactive job controller.  It lets you run several interactive
Xjobs simultaneously.  Before running BOSS put
X
X    $ boss :== $usr:[utility]boss
X
Xinto your login.com file.  In order to run BOSS type
X
X    $ boss
X
XBOSS was written by Charles Karney based on the PHOTO program written by Asbed
XBedrossian of USC.  It utilizes the Pseudo TTY package of Kevin Carosso of
XHughes Aircraft Co.
X
XBugs, questions, etc. to Charles Karney (Karney@PPC).
X2 Description
XBOSS lets you create up to 8 processes each of which is identified by a
Xsingle letter (A thru Z).  This letter is used in the process name and in
Xthe DCL prompt.  At most one of these processes is `current'.  This means
Xthat what you type is sent to that process, and output from that process is
Xsent to your terminal.  A process which is not current can run but cannot do
Xoutput.  (Output is saved until you make that process current.)
X
XYou can run any program under BOSS.  For example, you might
X    run Emacs or EVE                   in process E
X    SET HOST to the EPX                in process H
X    run NETTY to the B machine         in process B
X    do a FORTRAN compilation           in process F
X    execute DCL commands               in process D
X    talk to your colleague using PHONE in process P
Xand so on.
X
XOf course, you would normally not need to run so many processes.  (Indeed
Xyour subprocess quota may only let you run 5 processes.)  When you are
Xthrough with a process, you should log out of it (with `logout') and switch
Xback to some other process.
X
XBOSS makes no attempt to keep track of what is on your screen.  Usually when
Xswitching to a process which manages the screen in an advanced manner, you
Xshould issue a command to the program to get it to re-draw the screen.
X(This is control-w for EVE, PHONE, SPELL; control-l for Emacs.)
X
XBOSS uses the VT100 escape sequences for clearing the screen, etc.  However
Xit should still be useable on non-VT100-compatible terminals.
X2 Commands
XUsually, all commands to BOSS begin with the C-\ (control-\).  The exception
Xis when there is no current process (i.e., initially and immediately after
Xlogging out of a process).  In that case the C-\ is optional.
X
XThe commands are:
X
X    C-h (or BS) Print command summary
X    C-z         Quit (asking confirmation if there are processes)
X    a thru z    Switch to a particular process (starting it if necessary)
X    A thru Z     the same except clear the screen first
X    ?           List processes (* means current, + means waiting for output)
X    C-\         Send a real C-\ to the current process
X    DEL         Do nothing
X    other       Sound the bell on the terminal
X2 Bugs
XBOSS does single character input.  This is rather slow.  Don't expect it to
Xbe able to keep up with lots of data coming from the terminal.
X
XThe output on a Visual 550 at 9600 baud occasionally has glitches in it.
XThis is because the Visual 550 needs flow control enabled to operate at
X9600 baud, but BOSS doesn't react quickly enough to the control-s sent by
Xthe terminal.  The solution is to run at 4800 baud or slower.
X
XOutput gets garbled when using BOSS via SET HOST (i.e., SET HOST followed by
XBOSS).  This happens when you type while output is coming to your terminal.
XThe symptom is that the lines come out in the wrong order.  It's OK to use
XSET HOST while in BOSS (i.e., BOSS followed by SET HOST).
X
XPC file transfer (e.g., using MACX, XMODEM) probably doesn't work through
XBOSS.  (Actually I have got downloads to work with MACX.  That presumably is
Xan accident of the Mac not sending a C-\ as part of the handshaking.
XUploads seem to stall.)
X
XAttempting to attach to the process running BOSS from one of its
Xsubprocesses causes a hangage.
X2 Unfeatures
XThe following features are not implemented but are possible future
Xenhancements.
X
X* Log files.
X* Largish output buffer for non-current processes (have to worry about
X  controlling the output though).  Sending a C-s won't work.
X* Ability to kill particular processes.
X* Ability to ATTACH to non-BOSS processes.  I haven't managed to make this
X  work yet.
X* Configurable for other terminals.
X* Allow programs to talk back to BOSS to do process switching
X* Allow default directory to propagate to other processes.
$ GoSub Convert_File
$ Goto Part2

KARNEY%PPC.MFENET@NMFECC.ARPA (08/25/87)

$Part2:
$ File_is="BOSS.C"
$ Check_Sum_is=1078629640
$ Copy SYS$Input VMS_SHAR_DUMMY.DUMMY
X/* BOSS interactive job controller.
X
XVersion 1.0.  August 22, 1987.
X
XWritten by
X    Charles Karney
X    Plasma Physics Laboratory   Phone:   609/683-2607
X    Princeton University        MFENet:  Karney@PPC.MFENET
X    PO Box 451                  ARPANet: Karney%PPC.MFENET@NMFECC.ARPA
X    Princeton, NJ 08544-0451    Bitnet:  Karney%PPC.MFENET@ANLVMS.BITNET
X
XBased on the PHOTO program of Asbed Bedrossian (USC, asbed@oberon.usc.edu).
X
XIt utilizes the Pseudo TTY package of Kevin Carosso
X(Hughes Aircraft Co., kvc@engvax.scg.hac.com, kvc%engvax@oberon.usc.edu).
X
XBOSS lets you create up to 8 processes each of which is identified by a
Xsingle letter (A thru Z).  This letter is used in the process name and in
Xthe DCL prompt.  At most one of these processes is `current'.  This means
Xthat what you type is sent to that process, and output from that process is
Xsent to your terminal.  A process which is not current can run but cannot do
Xoutput.  (Output is saved until you make that process current.)
X
XCompile and link with
X    $ cc boss
X    $ link/notraceback boss,sys$library:vaxcrtl/lib
X
XInstall with
X    $ install :== $install/command_mode
X    $ if  f$file("usr:[utility]boss.exe","known") then -
X        install delete usr:[utility]boss
X    $ install create usr:[utility]boss/priv=phy_io
X*/
X
X#include DESCRIP
X#include IODEF
X#include TTDEF
X#include TT2DEF
X#include JPIDEF
X#include stdio
X
X#define  ctlchar        28      /* Control character ^\ */
X#define  ttchrlen       12
X#define  tpdevlen       15
X#define  mbsiz          40
X#define  maxsiz         80
X#define  imagelen       80
X#define  linesz        512
X#define  nproc           8      /* Number of process allowed */
X#define  nalph          26      /* Number of possible names */
X#define  clr     "\033[r\033[H\033[2J" /* Clear screen reset scroll */
X#define  bos     "\033[r\033[99;1H" /* Go to bottom of screen */
X#define  ceol    "\033[K"       /* Clear to end-of-line */
X#define  ceoln   "\033[K\r\n"   /* Clear to end-of-line and newline */
X#define  bad(j)         !(j & 1)
X#define  check(a)       st=a; if (bad(st)) LIB$SIGNAL(st)
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
Xint
X  py_chn[nproc], py_mb_chn[nproc], tt_chn, tt_mb_chn,
X  pid[nproc], st, cur, count[nproc], procno[nalph];
X
Xchar
X  buf[100],image[imagelen],
X  finaltp[nproc][tpdevlen],
X  py_mb[nproc][mbsiz], tt_mb[mbsiz],
X  input_char, tpline[nproc][linesz],
X  blocked[nproc],
X  enable_hangups[nproc], name[nproc],
X  pending = 0, quit_pending = 0;
X
Xstruct CHARBLK tt_chr, tt_sav_chr;
Xstruct IOSBBLK tiosb, piosb[nproc], miosb[nproc];
X
Xquit()                         /* This is done upon exiting, by exit handler */
X{
X  int i,j;
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
Xcomp_srv(n)                     /* AST for completion of processes */
Xint n;
X{
X  int j;
X
X  j = SYS$DELMBX(py_mb_chn[n]);
X  if (name[n]) procno[name[n] - 'A'] = -1;
X  name[n] = '\0';
X  if (cur == n) {
X    cur = -1;
X    pending = 1;
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;
X  char proc[20],prompt[4];
X  $DESCRIPTOR(d_pty_io, pty_io); /* PTY name + number */
X  $DESCRIPTOR(d_proc, proc);   /* Process name */
X  $DESCRIPTOR(d_prompt, prompt); /* Prompt */
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  strcpy(prompt,"A> ");
X  prompt[0] = name;
X  d_prompt.dsc$w_length = strlen(prompt);
X  st = LIB$SPAWN(0,&d_pty_io,&d_pty_io,&flg,&d_proc,pid,0,0,
X                &comp_srv,n,&d_prompt,0);
X  return(st);
X}
X
Xpy_srv(n)                       /* AST reads on pseudo terminal */
Xint n;
X{
X  check(piosb[n].stats);        /* Check status */
X  count[n] = piosb[n].tmoff + piosb[n].tmsiz; /* How much was read */
X  if (n == cur) term_out(n);    /* Write the stuff to the terminal */
X  else blocked[n] = 1;
X}
X
Xterm_out(n)
Xint n;
X{
X  check(SYS$QIO(1,tt_chn,IO$_WRITEVBLK,&tiosb,0,0,
X                &tpline[n],count[n],0,0,0,0));
X  check(SYS$WAITFR(1));         /* for some reason QIOW does not work */
X  check(SYS$QIO(0,py_chn[n],IO$_READVBLK,&piosb[n],&py_srv,n,
X                &tpline[n],linesz,0,0,0,0)); /* Queue next AST */
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*",name[j]);
X        else if (blocked[j]) sprintf(bufa," %c+",name[j]);
X        else sprintf(bufa," %c ",name[j]);
X        strcat(buf,bufa);
X      }
X    }
X    strcat(buf,"] ");
X    strcat(buf,ceoln);
X  }
X  else sprintf(buf,"\r[No processes] %s",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  check(SYS$QIOW(0,tt_chn,IO$_WRITEVBLK,0,0,0,msg,strlen(msg),0,0,0,0));
X}
X
Xchar *get_image(pid)           /* Get the image name for a process */
X     int pid;
X{
X  int j, item, len;
X  char *ptr, *ptra;
X  $DESCRIPTOR(d_image,image);
X  item = JPI$_IMAGNAME;
X  j = LIB$GETJPI(&item,&pid,0,0,&d_image,&len);
X  ptr = &image;
X  if (bad(j)) strcpy(image,"<UNAVAIL>");
X  else if (image[0] == ' ') strcpy(image,"DCL");
X  else {
X    if ((ptr = strrchr(image,']'))) ptr++;
X    else ptr = &image;
X    if (ptra = strchr(ptr,'.')) *ptra = '\0';
X  }
X  return(ptr);
X}
X
Xtt_srv()                        /* AST: Read on real terminal */
X{
X  int i, ncur;
X  char post, nname, *prefix;
X
X  check(tiosb.stats);
X                                /* Read everything typed right away */
X  post = 1;
X  if (quit_pending) {
X    if (toupper(input_char) == 'Y') {
X      term_msg(" Yes\r");
X      exit(1);
X    } else {
X      post = 0;
X      pending = cur < 0;
X      quit_pending = 0;
X      term_msg(" No\r\n");
X    }
X  }
X  else if (pending) {
X    post = 0;
X    if (input_char == '\032') { /* Ctrl-Z quits */
X      if (count_processes()) {
X        sprintf(buf,"%s[Do you really want to quit (y or n)?]%s\007",bos,ceol);
X        term_msg(buf);
X        quit_pending = 1;
X      }
X      else exit(1);
X    }
X    else if (input_char == '\010') {
X      sprintf(buf,"%sBOSS commands are preceded by C-\\ (control-\\).  \
XThe commands are:%s",bos,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,"\r    a thru z    Switch to another process%s",ceoln);
X      term_msg(buf);
X      sprintf(buf,"\r    A thru Z     the same except clear the screen \
Xfirst%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-\\         Send a real C-\\ to the current \
Xprocess%s",ceoln);
X      term_msg(buf);
X      sprintf(buf,"\rType HELP BOSS for more information.%s",ceoln);
X      term_msg(buf);
X    }
X    else if (input_char == '?') diag();
X    else {
X      nname = toupper(input_char);
X      if (nname >= 'A' && nname <= 'Z') {
X        if (input_char < 'a') prefix = clr; /* Clear if upper case */
X        else prefix = bos;
X        if ((cur >= 0) && (name[cur] == nname)) { /* Redundant move */
X          sprintf(buf,"%s[Already in process %c, %s]%s",
X                  prefix,nname,get_image(pid[cur]),ceoln);
X          term_msg(buf);
X        }
X        else if ((ncur = procno[nname-'A']) >= 0) { /* Existing proc */
X          cur = ncur;
X          sprintf(buf,"%s[Switch to process %c, %s]%s",
X                  prefix,name[cur],get_image(pid[cur]),ceoln);
X          term_msg(buf);
X          if (blocked[cur]) term_out(cur);
X        }
X        else if ((ncur = next_slot()) < 0) {
X          if (cur >= 0)
X            sprintf(buf,"%s[No process slots left--still in %c]%s",
X                    bos,name[cur],ceoln);
X          else sprintf(buf,"%s[No process slots left]%s",bos,ceoln);
X          term_msg(buf);
X        }
X        else {
X          sprintf(buf,"%s[Starting process %c...%s",prefix,nname,ceol);
X          term_msg(buf);
X          if (bad(fire_up(ncur,nname))) {
X            if (cur >= 0)
X              sprintf(buf,"failed!!\007--still in %c]%s",name[cur],ceoln);
X            else
X              sprintf(buf,"failed!!\007]%s",ceoln);
X            term_msg(buf);
X          } else {
X            sprintf(buf,"done; now in process %c, %s]%s\r",
X                    nname,get_image(pid[ncur]),ceol);
X            term_msg(buf);
X            cur = ncur;
X            if (blocked[cur]) term_out(cur);
X          }
X        }
X      } else {
X        if (input_char != ctlchar) {
X          if (input_char != '\177') term_msg("\007");
X        }
X        else post = 1;
X      }
X    }
X    pending = cur < 0;
X  }
X  else if (input_char == ctlchar) {
X    post = 0;
X    pending = 1;
X  }
X  if ( post && (cur >= 0) ) {  /* write everything we read to pseudo-term */
X    check(SYS$QIOW(0,py_chn[cur],IO$_WRITEVBLK,&tiosb,0,0,
X                   &input_char,1,0,0,0,0));
X    check(tiosb.stats);
X  }
X                               /* re-post read AST on real term */
X  check(SYS$QIO(0,tt_chn,IO$_READVBLK,&tiosb,&tt_srv,0,
X                &input_char,1,0,0,0,0));
X}
X
Xget_tt_info()
X{
X  $DESCRIPTOR(d_tt, "SYS$COMMAND");
X                                /* Get a channel & mailbox of terminal */
X  check(LIB$ASN_WTH_MBX(&d_tt,&mbsiz,&maxsiz,&tt_chn,&tt_mb_chn));
X                                /* Get the terminal characteristics. */
X  check(SYS$QIOW(0,tt_chn,IO$_SENSEMODE,0,0,0,&tt_chr,ttchrlen,0,0,0,0));
X  tt_sav_chr = tt_chr;
X  tt_chr.ttchr |= TT$M_NOECHO;  /* term will be Noecho */
X  tt_chr.ttchr &= ~TT$M_HOSTSYNC & ~TT$M_TTSYNC; /* it will have ^S */
X  tt_chr.xchar |= TT2$M_PASTHRU; /* it will be PASTRHU */
X  check(SYS$QIOW(0,tt_chn,IO$_SETMODE,0,0,0,&tt_chr,ttchrlen,0,0,0,0));
X}
X
Xfix_a_tp(n)                             /* Set up a Pseudo term */
Xint n;
X{
X  int f1[3], tp_chn;
X  struct IOSBBLK iosb;
X
X  $DESCRIPTOR(d_pynam,"PYA0:"); /* Template. */
X  $DESCRIPTOR(d_finaltp, &finaltp[n]);
X                                /* Assign a mailbox to PYA */
X  check(LIB$ASN_WTH_MBX(&d_pynam,&mbsiz,&maxsiz,&py_chn[n],&py_mb_chn[n]));
X                                /* this gives us a TPA number via SENSEMODE */
X  check(SYS$QIOW(0,py_chn[n],IO$_SENSEMODE,&iosb,0,0,&f1,ttchrlen,0,0,0,0));
X  sprintf(&finaltp[n],"TPA%d:",iosb.tmntr); /* see? */
X  d_finaltp.dsc$w_length = strlen(&finaltp[n]);
X  check(SYS$ASSIGN(&d_finaltp,&tp_chn,0,0));
X                                /* Get a channel on this TPA */
X                                /* Make it look like a terminal */
X  if (bad(SYS$QIOW(0,tp_chn,IO$_SETCHAR,0,0,0, /* This needs PHY_IO priv */
X                   &tt_sav_chr,ttchrlen,0,0,0,0)))
X    check(SYS$QIOW(0,tp_chn,IO$_SETMODE,0,0,0,
X                   &tt_sav_chr,ttchrlen,0,0,0,0));
X  check(SYS$DASSGN(tp_chn));    /* We don't need it. only the mailbox */
X                                /* in fact keeping it kills us. */
X}
X
Xpost_term_reads()                           /* Read AST on real term */
X{
X  check(SYS$QIO(0,tt_mb_chn,IO$_READVBLK,&tiosb,0,0,
X                &tt_mb,mbsiz,0,0,0,0));
X  check(SYS$QIO(0,tt_chn,IO$_READVBLK,&tiosb,&tt_srv,0,
X                &input_char,1,0,0,0,0));
X}
X
Xpost_pty_reads(n)                          /* Read AST on Pseudo-term */
Xint n;
X{
X  check(SYS$QIO(0,py_mb_chn[n],IO$_READVBLK,&miosb[n],0,0,
X                &py_mb[n],mbsiz,0,0,0,0));
X  check(SYS$QIO(0,py_chn[n],IO$_READVBLK,&piosb[n],&py_srv,n,
X                &tpline[n],linesz,0,0,0,0));
X}
X
Xint
Xfire_up(n,nname)                /* Fire up subprocess n */
Xint n;
Xchar nname;
X{
X  int st;
X  name[n] = nname;
X  procno[nname - 'A'] = n;
X  count[n] = 0;                 /* Initialize buffer count */
X  blocked[n] = 0;               /* It starts unblocked */
X  enable_hangups[n] = 0;
X  fix_a_tp(n);                  /* Set a pseudo terminal by TT info */
X  check(SYS$CANCEL(py_chn[n])); /* Don't need this Half of pseudo-ter */
X  st = low_lib_spawn(n,&finaltp[n],&pid[n],name[n]); /* Spawn a subprocess. */
X  if (!bad(st)) post_pty_reads(n); /* Set up AST */
X  else comp_srv(n);             /* Mark the process as non-existent */
X  return(st);
X}
X
Xinitialize()                    /* Initialize everything */
X{
X  int j;
X  for (j = 0; j < nproc; j++) name[j] = '\0'; /* Initialize variables */
X  for (j = 0; j < nalph; j++) procno[j] = -1;
X  cur = -1;
X  pending = 1;
X  quit_pending = 0;
X  get_tt_info();                /* Initialize terminal */
X  post_term_reads();
X}
X
Xmain( )
X{
X  int  exit_handler[4] = {0,quit,0,&st};
X
X  check(SYS$DCLEXH(&exit_handler)); /* Define Exit handler (quit) */
X  printf("Begin BOSS\nType control-\\ control-h for information\n\n");
X  initialize();
X  sys$hiber();
X}
$ GoSub Convert_File
$ Exit