Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!uunet!seismo!rutgers!ames!ucbcad!ucbvax!NMFECC.ARPA!KARNEY%PPC.MFENET From: KARNEY%PPC.MFENET@NMFECC.ARPA Newsgroups: comp.os.vms Subject: BOSS interactive job controller source (part 2 of 2) Message-ID: <870825084451.00o@NMFECC.ARPA> Date: Tue, 25-Aug-87 11:44:51 EDT Article-I.D.: NMFECC.870825084451.00o Posted: Tue Aug 25 11:44:51 1987 Date-Received: Thu, 27-Aug-87 07:00:47 EDT Sender: daemon@ucbvax.BERKELEY.EDU Organization: The ARPA Internet Lines: 445 $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 = ℑ X if (bad(j)) strcpy(image,""); X else if (image[0] == ' ') strcpy(image,"DCL"); X else { X if ((ptr = strrchr(image,']'))) ptr++; X else ptr = ℑ 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