$! ------------------ CUT HERE ----------------------- $ v='f$verify(f$trnlnm("SHARE_VERIFY"))' $! $! This archive created by VMS_SHARE Version 7.1-004 3-AUG-1989 $! On 16-OCT-1992 14:19:21.72 By user KARNEY $! $! This VMS_SHARE Written by: $! Andy Harper, Kings College London UK $! $! Acknowledgements to: $! James Gray - Original VMS_SHARE $! Michael Bednarek - Original Concept and implementation $! $!+ THIS PACKAGE DISTRIBUTED IN 6 PARTS, TO KEEP EACH PART $! BELOW 54 BLOCKS $! $! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER $! AND EXECUTE AS A COMMAND PROCEDURE ( @name ) $! $! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING: $! 1. BOSS.README;25 $! 2. BOSS.HLP;97 $! 3. BOSS.C;278 $! 4. BOSS_CLD.CLD;33 $! 5. BOSS_BUILD.COM;2 $! 6. BOSS_INSTALL.COM;1 $! $set="set" $set symbol/scope=(nolocal,noglobal) $f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID")) $e="write sys$error ""%UNPACK"", " $w="write sys$output ""%UNPACK"", " $ if f$trnlnm("SHARE_LOG") then $ w = "!" $ if f$getsyi("version") .ges. "V4.4" then $ goto START $ e "-E-OLDVER, Must run at least VMS 4.4" $ v=f$verify(v) $ exit 44 $UNPACK: SUBROUTINE ! P1=filename, P2=checksum $ if f$search(P1) .eqs. "" then $ goto file_absent $ e "-W-EXISTS, File ''P1' exists. Skipped." $ delete/nolog 'f'* $ exit $file_absent: $ if f$parse(P1) .nes. "" then $ goto dirok $ dn=f$parse(P1,,,"DIRECTORY") $ w "-I-CREDIR, Creating directory ''dn'." $ create/dir 'dn' $ if $status then $ goto dirok $ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped." $ delete/nolog 'f'* $ exit $dirok: $ w "-I-PROCESS, Processing file ''P1'." $ define/user sys$output nl: $ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1' PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET( SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name"); buff:=CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(buff)) ;LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION( BEGINNING_OF(buff));g:=0;LOOP EXITIF MARK(NONE)=END_OF(buff);x:= ERASE_CHARACTER(1);IF g = 0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x= "V" THEN APPEND_LINE;MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF; IF x="+" THEN g:=1;ERASE_LINE;ENDIF;ELSE IF x="-" THEN g:=0;ENDIF;ERASE_LINE; ENDIF;ENDLOOP;p:="`";POSITION(BEGINNING_OF(buff));LOOP r:=SEARCH(p,FORWARD); EXITIF r=0;POSITION(r);ERASE(r);COPY_TEXT(ASCII(INT(ERASE_CHARACTER(3)))); ENDLOOP;o:=GET_INFO(COMMAND_LINE,"output_file");WRITE_FILE(buff,o); ENDPROCEDURE;Unpacker;EXIT; $ delete/nolog 'f'* $ CHECKSUM 'P1' $ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT $ e "-E-CHKSMFAIL, Checksum of ''P1' failed." $ ENDSUBROUTINE $START: $ create/nolog 'f' XThis is BOSS version 4.3 (June 2, 1992). It consists of 6 files X BOSS.README`009 This file X BOSS.HLP`009 The user help file X BOSS.C`009 The source code X BOSS_CLD.CLD The command language definitions X BOSS_BUILD.COM The procedure for compiling and linking BOSS X BOSS_INSTALL.COM The procedure for installing BOSS X XBOSS requires that pseudo TTY (PTY) drivers be installed on your system. XThis should be the latest version posted to INFO-VAX by Kevin Carosso in XAugust 1988. This is recommended version for both VMS 4.x and VMS 5.0. XContact me if you need a copy of the PTY drivers. Alternatively, BOSS Xwill run with the FTdriver. It is currently set up to do so, but can Xuse the PY/TW driver combo instead; just edit the compile time conditional. X XIf you plan to use BOSS/UW (to get multi-window operation on a Macintosh), Xyou will need the UW terminal emulator. I can send you that too. X XYou should edit BOSS_INSTALL.COM to refer to the directory where BOSS.EXE Xresides. BOSS should be installed with both PHY_IO and OPER privileges. XYou can get by without these privileges--see the comments in BOSS.C. X XBOSS needs to be defined as a foreign command, i.e., X $ BOSS == "$:`091`093BOSS" XBOSS.HLP tells the user to do X $ SETUP BOSS Xbefore running BOSS. SETUP on our system runs a .COM file which does the Xnecessary initialization for various utilities. You will probably need to Xedit BOSS.HLP to insert the incantation appropriate for your site. XBOSS.HLP should of course be installed in some easily accessible help Xlibrary. Something like X $ LIBRARY/HELP/REPLACE HLP$LIBRARY_1 BOSS Xshould do the trick. X X Charles Karney `032 X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2160 X X---------------------------------------------------------------------------- V-- X XThe remainder of this file is specific to people running BOSS/UW. X XThe user documentation is in HELP BOSS Windows and its subtopics. X XYou will get a separate mailing containing the three files X UNIX-UW-42.HQX`009The UW terminal emulator and documentation X UWPROTO.TXT`009`009Internal documentation on UW protocols X MACMOUSE.EL`009`009Mouse support for Gnu Emacs X XUNIX-UW-42.HQX should be downloaded to a Mac as a text file and run through Xthe BinHeX and Packit programs to give uw (the terminal emulator) and Xuw.doc (the documentation in MacWrite format). X XUWPROTO.TXT describes the protocol used by UW and BOSS/UW. Can be ignored Xif you like. X XIf you have Gnu Emacs: X XMACMOUSE.EL should be moved to EMACS_LIBRARY:`091LISP`093. XAdd a uw entry in EMACS_LIBRARY:`091ETC`093 with: X X# Macintosh/UW termcap (same as Mac without the cs, and has km = meta) Xd0`124uw`124uw-am`124unix-windows:\ X`009:cr=`094M:do=`094J:nl=`094J:bl=`094G:co#80:li#24:cl=50`094O\E`091;H\E`09 V12J:\ X`009:le=`094H:bs:am:cm=5\E`091%i%d;%dH:nd=2\E`091C:up=2\E`091A:\ X`009:ce=3\E`091K:cd=50\E`091J:so=\E`0917m:se=\E`091m:us=\E`0914m:ue=\E`091m: V\ X`009:md=\E`0911m:mr=\E`0917m:mb=\E`0915m:me=\E`091m:is=\E`0911;24r\E`0914l\E V`09124;1H:\ X`009:rs=\E>\E`091?3l\E`091?4l\E`091?5l\E`091?7h\E`091?8h:\ X`009:ks=\E=\E`091?1h:ke=\E>\E`091?1l:\ X`009:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=`094H:\ X`009:ho=\E`091H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:ta=`094I:pt:sr=5\EM:vt#3:xn: V\ X`009:ic=7\E`0911@:dc=7\E`0911P:al=9\E`0911L:dl=9\E`0911M:\ X`009:sc=\E7:rc=\E8:\ X`009:IC=7\E`091%d@:DC=7\E`091%dP:AL=3*\E`091%dL:DL=3*\E`091%dM:km: X XPostscript: X XI still prefer VersaTerm PRO to UW, even though it doesn't have multi- Xwindow support. There are too many VersaTerm features that I need which Xare absent in UW. X XI've only implemented the most basic level of UW service under BOSS X(protocol 1 in UWPROTO.TXT). The next level allows windows to be retitled Xfrom the VAX, as well as setting many of the other attributes of windows. XThis will most likely not get implemented, unless multi-window support Xappears in VersaTerm. X XThe main reason for implementing the UW features in BOSS was to show that Xthe Macintosh can provide a multi-window enviroment for the VAXes. Now we Xhave to get Lonnie Abelbeck to modify VersaTerm to support the UW Xprotocol... X XNote that Meshugena-term on Amiga, as well as UW on Amiga, support the UW Xprotocol. $ CALL UNPACK BOSS.README;25 524441163 $ create/nolog 'f' X1 BOSS XBOSS is an interactive job controller. It lets you run several interactive Xjobs simultaneously. Before running BOSS put X X $ SETUP BOSS X Xinto your login.com file. In order to run BOSS type X X $ BOSS X XBOSS can operate in one of two modes: X* regular mode. This works with any terminal. See subtopic Description for X an overview. X* multi-window mode; this ONLY works with a Macintosh running the UW termina Vl X emulator. See subtopic Windows for an overview and further details. X2 Description XBOSS lets you create up to 8 processes on a VAX/VMS system. Each process is Xidentified by a single letter (A thru Z). This letter is used in the Xprocess name and in the DCL prompt. At most one of these processes is X`096current'. What you type is sent to that process, and output from that Xprocess is sent to your terminal. A process which is not current can run Xbut normally cannot do output. (What happens to the output is governed by Xthe output flag for a particular process. See topic Output_flags.) You Xusually switch between processes by typing control-\ followed by the Xidentifying letter. It is also possible to have have of your processes Xinitiate the switch. (See topic Communicating.) X XYou can run any program under BOSS. For example, you might X run Emacs or EVE in process E X SET HOST to another machine 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 `096logout') and swit Vch Xto 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 XHowever, you can GET Boss to remember things on your screen by giving the XControl-J and control-I commands, which cause BOSS to remember what is typed Xto your screen for the last 4000 characters and restore it when returning to Xyour process. You can also get BOSS to record output to a virtual terminal Xin a file BOSS.LOG (where is the 1-character process name) with the Xcontrol-L command. X XBOSS uses needs to know the escape sequences for clearing your screen, etc. XBy default, it uses the VT100 sequences which work for a wide range of Xterminals. See topic Terminal_types. X2 Commands `032 XUsually, all commands to BOSS begin with the command character which by Xdefault is C-\ (control-\). The command character can be changed by using Xthe /COMMAND_CHARACTER qualifier to BOSS. The command character is not Xrequired when there is no current process (i.e., initially and immediately Xafter logging out of a process). In that case the command character is Xoptional. X XThe commands are: X X C-h (or BS) Print command summary X C-z Quit (asking confirmation if there are processes) X C-x Quit after the last process has terminated X a Switch to process labeled A (and similarly with a thru z) X A Clear screen and then switch to process A X C-n a Create new process A as a subprocess (C-n A clears screen first) X C-t a Create process A at top level (C-t A clears screen first) X C-k Kill the current process (asks for confirmation) X C-b Buffer output for this process X C-o Discard output for this process X C-p Print output from this process X C-w Stop output from this process X C-i Toggle buffering active output X C-j Toggle keeping buffer for more than 1 X process transition X C-l (ell) Toggle logging to BOSSn.LOG. Separate logfiles to X each process are kept and logging is of what is X sent to the pseudoterminal, not the real one, so X you can log a process that is in discard-output mode. X C-v Toggle logging to BOSSn.LOG. Similar to C-L except X`009`009that C-L logging suspends the logfile write when X`009`009toggled off again, and C-V logging closes the log X`009`009file when toggled off. X C-e Toggle logging. This is similar to C-l except that it X `009`009closes the logfile when it stops logging. Thus you X`009`009can use C-l when you need to log several items but X`009`009want to skip the material between, keeping all the X`009`009logged data in one file. Use control-E to log a bit X`009`009of a session which you can then examine in a second X`009`009session, without having to leave BOSS. Note that X`009`009logging must be on to close the file. X C-g n Allows saving of n lines of buffered output (needs to be X in C-i C-j mode) and replaying them into the next X process you switch to, enabling cut/paste. X +`009 Enter command mode for one line X ? List processes and output flags X (* means current, +/- means waiting for output) X C-\ Sends the command character to the current process X DEL Do nothing X other Sound the bell on the terminal X X Command mode allows one command to be entered. This is done with a Xnormal $QIOW, so should be used for setup, as it may cause character XASTs to be lost if used in heavy activity. A number of commands are Xsupported, short to minimize time needed to enter them: X X Schars Sets current process to get chars (up to 7 of them) X`009when the process is switched to. A common use will be X`009S`094W, where "`094W" means the control-W character, which X`009gets many fullscreen applications to repaint the screen. X Gchars Like Schars but sets the prefix for all processes. The X`009prefix is initially nonexistent. X Enumber Causes the terminal buffer to only write "number" characters X`009to the screen on a process switch where `094I and `094J modes X`009are active. Otherwise the entire saved buffer is dumped X`009on each switch, which may be more than is desired. The X`009value is clamped between 100 and the buffer size. Enumber X`009affects only the current process. X Gnumber Like Enumber, but resets the output size for all processes. X X`009The Enumber and Gnumber commands are designed to allow one to X`009buffer a large number of characters, but only display a X`009smaller number on context switches. Reissuing the commands X`009with a larger value of "number" will allow the rest to be X`009seen. Also, if `094I`094J mode is not in use, the entire buffer X`009is displayed as was the case in earlier versions of BOSS. X X2 Qualifiers XWhen starting BOSS you can provide the following qualifiers: X X/COMMAND_CHARACTER X /COMMAND_CHARACTER=num X Default: /COMMAND_CHARACTER=%O34 (i.e., C-\) X XUse the character whose ASCII code is num as the command character instead Xof C-\. E.g., X BOSS/COMMAND_CHARACTER=%X1F ! set command character to C-_ X BOSS/COMMAND_CHARACTER=%O37 ! the same X BOSS/COMMAND_CHARACTER=31 ! the same X BOSS/COMMAND_CHARACTER='F$CVSI(0,6,"_")' ! the same X BOSS/COMMAND_CHARACTER='F$CVSI(0,8,"`096")' ! set to `096 (backquote) XRepeating the command character twice sends the character to the current Xprocess. C-z is disallowed as a command character since otherwise you Xwouldn't be able to quit. X X/START_PROCESS X /START_PROCESS=(process-1,process-2,...) X XBOSS immediately starts up the specified processes. E.g., X BOSS/START_PROCESS=A Xstarts process A. You are left in the last process specified; e.g., X BOSS/START_PROCESS=(E,D) Xstarts E and D and sets D to be the current process X X/STUFF_STRING X /STUFF_STRING=(string-1,string-2,...) X XThis qualifier is processed in parallel with /START_PROCESS. string-n is Xsent the process-n when it is started. A carriage return is added to the Xstring unless the string is empty. If the /STUFF_STRING list is shorter Xthan the /START_PROCESS list, then nothing is sent to the remaining Xprocesses. E.g., X BOSS/START=(E,D)/STUFF=EMACS Xstarts process E runs Emacs in it. Then BOSS starts process D (and sends Xnothing to it). To send more than one command to a process, you can do, Xe.g., X BOSS/START=(B,B)/STUFF=("SHOW TIME",FINGER) Xwhich start process B and sends runs both SHOW TIME and FINGER. (Or else Xyou can construct a DCL string with an imbedded carriage return. X X/AUTO_STUFF_STRING X /AUTO_STUFF_STRING=string X XThis specifies a string to stuff into each newly created subprocess. A Xcarriage return is added to the string unless the string is empty. This Xgets sent to the subprocess before the strings specified by /STUFF_STRING Xor BOSS$STUFF. Top-level processes are unaffected by this qualifier. XThere are three applications where this would be useful. (1) If BOSS is Xnot installed with PHY_IO privilege (so that subprocesses don't Xautomatically inherit the parents terminal type), then use, e.g., X BOSS/AUTO_STUFF="SET TERM/VT100" X(2) If you are a privileged used and you want to be able to select any of Xyour authorized privileges in each subprocess, but you don't want them Xturned on by default, then use X $ DEFPRIV = F$GETJPI("","PROCPRIV") X $ SET PROCESS/PRIV=ALL X $ BOSS/AUTO_STUFF="SET PROCESS/PRIV=(NOALL,''DEFPRIV')" XThis way each subprocess will have your standard set of current and Xauthorized privileges. (Note that the authorized privileges for a Xsubprocess are set from the current privileges of its parent.) X(3) You want to turn off some classes of broadcasts in subprocesses. X BOSS/AUTO_STUFF="SET BROAD=NOSHUTDOWN" XYou will normally still receive such broadcasts when BOSS re-broadcasts Xthe broadcasts it receives to the current process. However, you will only Xreceive one copy of each broadcast. See also subtopic Broadcasts. X X/OUTPUT_FLAGS X /OUTPUT_FLAGS=(flag-1,flag-2,...) flag-n is one of b, o, w, p X XThis qualifier is processed in parallel with /START_PROCESS. The output Xflag for process-n is set to flag-n. If the /OUTPUT_FLAGS list is shorter Xthan the /START_PROCESS list, then the output flags for the remaining Xprocesses are set to the default. X X/DEFAULT_OUTPUT_FLAG X /DEFAULT_OUTPUT_FLAG=flag (one of b, o, w, p) X Default: /DEFAULT_OUTPUT_FLAG=b X XThis sets the default output flag. See topic Output_flags. X X/BEGIN_PROMPT X /BEGIN_PROMPT=string X Default: /NOBEGIN_PROMPT X XThis specifies the part of the DCL prompt which appears before the process Xlabel. E.g., X BOSS/BEGIN_PROMPT="--"/END_PROMPT=">> " Xgives you DCL prompts of the form "--Q>> ". X X/END_PROMPT X /END_PROMPT=string X Default: /END_PROMPT="> " X XThis specifies the part of the DCL prompt which appears after the process Xlabel. X X/SWITCH_CREATE X /SWITCH_CREATE X Default: /NOSWITCH_CREATE X XBy default, you have to create a process with either C-\ C-n x or C-\ C-t Xx. If /SWITCH_CREATE is set, then switching to nonexistent process Xcreates it as a subprocess. (I.e., C-\ x is equivalent to C-\ C-n x). If Xyou always want /SWITCH_CREATE set, then put X $ setup boss X $ boss == "''boss'/switch_create" Xinto your LOGIN.COM file. X X/PROCESS_DEFAULT X /PROCESS_DEFAULT=process-type (one of SUBPROCESS and TOP_LEVEL) X Default: /PROCESS_DEFAULT=SUBPROCESS X XThis governs the types of the processes created by /START_PROCESS, process Xswitching initiated by BOSS$SWITCH. (I.e., all process creation except for Xvia C-\ C-n x and C-\ C-t x.) X X/FLOW_CONTROL X /FLOW_CONTROL X Default: /NOFLOW_CONTROL X XNormally, everything you type is passed on to the current process. This Xincludes the flow-control characters control-s and control-q. This results Xin some delay in these characters being acted upon. Your terminal may Xtherefore receive many additional characters after a C-s is typed, causing Xyou to lose information off the top of your screen or your terminal's input Xbuffer to overflow. With X BOSS/FLOW_CONTROL XC-s and C-q are intercepted by the terminal driver and used as flow- Xcontrol. This cause C-s to be acted on more promptly. The drawback is Xthat you can never send C-s and C-q to your program. This breaks certain Xprograms, notably Emacs, which need to be able to receive all the ASCII Xcharacters. A second drawback is that once the output is stopped with C-s, Xonly a C-q can get it going again. You can't interrupt it with a C-y as Xyou can normally. (This is because BOSS/FLOW_CONTROL only treats C-s and XC-q as special. C-y and C-c are treated as ordinary characters.) X X/DELETE_CHARACTER X /DELETE_CHARACTER=num X Default: /DELETE_CHARACTER=%O177 (i.e., DEL) X XUse the character whose ASCII code is num as the delete character instead Xof DEL. This is useful on some terminals with weird keyboards. E.g., on Xsome ADM terminals, the delete key is shift-underscore. If you do X BOSS/DELETE_CHARACTER='F$CVSI(0,8,"_")' Xthen underscore and delete are interchanged. (I.e., the underscore key Xsends a delete to your program, and the shift-underscore key sends an Xunderscore to your program.) X X/UW X /UW X Default: /NOUW X XEnter BOSS in multi-window mode. You must be running the UW multi-window Xterminal emulator on a Macintosh computer. See topic Windows for more Xinformation. X X/RECORD X /RECORD`091=filespec`093 X Default: /RECORD=boss.record X XGenerate a file (boss.record by default) containing the keystrokes entered Xat the physical terminal, interspersed with timing information for later Xplayback. X`032 XThe timing is recorded as delay specifications of the form \, Xwhere is the delay in 100 millisecond units, and is a linefeed Xcharacter (hex 0A). Delays between keypresses that are less than a certain Xthreshold (currently 0.3 sec) will not be recorded. A "\" occurring as Xnormal character will be written to the session record file as "\\". X X/PLAYBACK X /PLAYBACK`091=filespec`093 X Default: /PLAYBACK=boss.record X`032 XPlayback a previously recorded session, see /RECORD. Upon reaching the end Xof the record file, Boss will switch from playback to interactive mode. The Xswitch to interactive will also happen if there is keyboard input, but see Xthe /LOCK qualifier for a way to prevent this. X XNB: in order to duplicate exactly the environment in which the session X is played back, you must make sure that Boss is started with the X same qualifiers as during recording, except for the playback X specific ones of course. X XSee also /GEAR to change the speed with which the session is replayed. X X/GEAR X /GEAR=I`091nfinite`093 or X /GEAR= X Default: /GEAR=1.0 X XUse /GEAR with the playback mode to speed up (or slow down) the replay. The Xspecified will be used as a multiplier for the delay specifiers Xencountered in the session record file. The default is 1.0, Xi.e. playback in real time. The value must be positive; specifying XI`091nfinite`093 will have the effect that delays are ignored completely. X`032 X/LOCK X /LOCK X Default: /NOLOCK X XLock the keyboard during a playback session. At the end of the record file, Xthe keyboard will be unlocked. X`032 XYou will need this if the applications that run issue commands to the Xterminal that cause the terminal to respond all by itself, for instance a X'set terminal/inquire' on DCL level, or if you don't want the user to Xinterfere with a playback session. In the absence of /LOCK, boss will Xterminate a playback session and switch to interactive mode as soon as it Xreceives data from the physical terminal. X X/QUIT_ON_IDLE X /QUIT_ON_IDLE X Default: /NOQUIT_ON_IDLE X`032 X Perform an automatic quit if there are no more processes active. This is X the equivalent of the control-x command (help topic "Commands"). X X/LOG X /LOG= X Default: /LOG=BOSS X XMake logging the default action when creating processes. See the description Xof the control-l command (help topic "Commands"). If the optional X is given, used that as the first part of the log file Xname, else use the string "BOSS" instead. The log file name will consist of Xthis prefix, followed by a 1-character name of the process and the string X".LOG". X2 Terminal_types XWhen switching processes, BOSS tries either to clear the screen or to move Xto the bottom of the screen. By default, it uses VT100 escape sequences for Xthese operations. However, if you define the logical name BOSS$TERM to be Xthe name of some other terminal, then it will use the escape sequence for Xthat terminal. X XE.g., if you're using an ADM3A terminal, you should do X $ DEFINE/NOLOG BOSS$TERM ADM3A Xbefore starting BOSS. (ADM3A users would probably also want to set the Xdelete character to underscore. See topic /DELETE_CHARACTER.) X XAt present BOSS only knows about three types of terminals: VT100, VT52, XADM3A, and UNKNOWN. The last choice makes minimal assumptions about the Xterminal, and should always give a reasonable display. X2 Process_types XBOSS deals with two types of processes: subprocesses and top-level Xprocesses. X XSubprocesses are what you get with the DCL command SPAWN. They inherit Xsymbols and logical names from the parent process (i.e., BOSS itself) at Xcreation time. The resources it uses count against the parent's quotas. XThe number of subprocesses is governed by your subprocess quota. XSubprocesses share the job logical name with the parent process. This gives Xa way for subprocesses to communicate with one another and with their Xparent. X XTop-level processes acts just like an entirely new login session (as though Xyou had done SET HOST 0). Indeed, you have to log in to get the process Xgoing. The resources that such processes use do not count against the Xparent's quotas. SHOW USERS will show that you are logged in multiple Xtimes. X XWhich type of process should you use? X XIn most cases subprocesses are best. These usually are quicker to get Xstarted (since you don't have to go through the login procedure again). XBOSS is able to set the process name and DCL prompt to include the process Xlabel. Synchronous switching to another process from a subprocess is Xpossible using the BOSS$SWITCH and BOSS$STUFF job logical names. X XWhen should you use a top-level process? Here are some cases: X* You need to log in as someone else. X* You need to run a large program that uses all of one of your quotas. X* You need to run with a different CLI. Log in with e.g., /CLI=SHELL. X* Your subprocess quota is too low to allow you to create subprocesses. X XType C-\ C-n a to start subprocess A; type C-\ C-t b to start top-level Xprocess B. X2 Output_flags XEach process has an output flag which may be set by C-\ followed by one of +-+-+-+-+-+-+-+- END OF PART 1 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ XC-b, C-o, C-p, or C-w (this sets the flag to b, o, p, or w, resp.). This Xflag governs what BOSS does to the output of a process which is not current. X(The current process always gets its output displayed immediately.) The Xmeanings of these settings are X X b Buffer output for this process. Output is saved in a 4k buffer. Buffer X is output when the process becomes current. The process hangs when this X buffer fills. This is useful for running a program which dribbles X output which you do not want to lose. In the process list (obtained by X C-\ ?), a - indicates that there is output ready to be displayed, and a X + indicates that the buffer is full (and the process is probably X hanging). X X o Discard output for this process. Only the most recent write will by X output when the process becomes current. This is useful for running a X program which periodically outputs some straightforward information such X as `096Processing record 103', where all you care about is the most rece Vnt X output. In the process list, + means that there is output available X (but the process is continuing to run). X X p Print output from this process. Output is output to the terminal X regardless of whether this is the current process or not. This is X useful if you need to be informed when a program completes. Also it can X be used to display status information periodically on your screen (see X subtopic Examples). X X w Stop output from this process. The process can do a single write which X will be accepted and saved by BOSS. The process will then hang when it X attempts to do the next write. In the process list + means that there X is output available (and the process is probably hanging). X XThe default output flag is b. The default can be changed by using the XDEFAULT_OUTPUT_FLAG qualifier or by issuing one of the flag setting commands Xwhen there is no current process (i.e., immediately after starting BOSS or Xafter logging out of a process). X XThe best setting of the output flag very much depends on your application. XYou will probably find the best setting to be b (the default). If one Xprocess is attempting to act synchronously with another, it may be necessary Xto set their output flags to w. However, if your synchronous switches are Xall performed via the BOSS$SWITCH mechanism, this isn't necessary since BOSS Xtemporarily sets the output flag to w on these types of process switches X(see topic Communicating). X XA potential problem with the b setting is that BOSS empties the buffer to Xyour terminal in a single operation. This may overflow your terminal's Xinput buffer (this is not a problem with a Mac running VersaTerm at 9600 Xbaud). This is not a problem if BOSS is used with the /FLOW_CONTROL Xqualifier (assuming that your terminal does flow control). X3 Examples XSuppose TIME.COM contains: X $ esc`0910,8`093=27 X $ sc = esc + "7" ! Save cursor X $ rc = esc + "8" ! Restore cursor X $ home = esc + "`091;76H" ! cursor to top right of screen X $ invert = esc + "`0917m" ! inverse video X $ revert = esc + "`091m" ! normal X $10$: X $ time = sc+home+invert+f$extract(12,5,f$time())+revert+rc X $ read/prompt="''time'"/end=43$/error=42$/time_out=0 sys$command dummy X $42$: X $ wait ::5 X $ goto 10$ X $43$: X XThis displays the time at 5 second intervals in the top right corner of Xthe screen. If this is running in a process whose output flag is p, the Xtime will displayed while in other processes. X2 Communicating XBOSS and the subprocesses under it can communicate via logical names. These Xonly work for BOSS's subprocesses, not for its top-level processes (because Xonly the subprocesses share the job logical name table with BOSS). The Xfollowing are recognized: X XBOSS$ID (in process table); BOSS defines this as the identifying letter of Xthe process. This can be used in tailoring the DCL prompt etc.; e.g., X $ set prompt "boss-''f$trnlnm("boss$id")'>" XIt can also be used to indicate to a program that it is running under BOSS. X XBOSS$SWITCH (in job table); whenever BOSS is writes output to the real Xterminal, it checks whether BOSS$SWITCH is defined. If it's defined as a Xsingle letter, BOSS will switch to that process and delete the logical name. XIf the process doesn't exist it is created as a subprocess. Thus a DCL Xprocedure can initiate a switch to process G with X $ define/job boss$switch g X $ write sys$error "" ! do some output to make BOSS wake up XThe switch takes place synchronously by setting the output flag for the Xoriginating process to w temporarily (see topic Output_flags). Both XBOSS$SWITCH and BOSS$STUFF should be defined as supervisor mode logical Xnames in the job table. They may be defined from programs with e.g., X status:=lib$set_logical('BOSS$SWITCH','D','LNM$JOB'); X XBOSS$STUFF (in job table); whenever a BOSS makes a process initiated switch. XIt stuffs the definition of BOSS$STUFF into the input stream of the process Xbeing switched to. After being used, BOSS$STUFF is deleted. X3 Examples XThe following command procedure will do a SHO DEF and leave SHO DEF in the Xrecall buffer: X $ cr`0910,8`093 = 13 X $ define/job boss$stuff "sho def''cr'" X $ define/job boss$switch 'f$trnlnm("boss$id")' X XHere's how to switch to process F and have the present job continue Xrunning: X $ define/job boss$switch f X $ char`0910,8`093 = 22 ! control-V X $ gosub out_char X $ return X $! X $out_char: ! Spit out the character X $ read/prompt='char'/end=40$/error=40$/time_out=0 sys$command dummy X $40$: return X XIf you want the present process to wait, then repeat the `096gosub out_char' Xthree times. X XReturn paths may be implemented via additional logical names. E.g., the Xprocedure that runs Emacs under BOSS does the following. X XIf Emacs isn't running (boss$emacs undefined) do X $ define/job boss$emacs 'f$trnlnm("boss$id")' Xand start Emacs. X XIf Emacs is running (boss$emacs defined) do X $ define/job boss$return_switch 'f$trnlnm("boss$id")' X $ define/job boss$switch 'f$trnlnm("boss$emacs","lnm$job")' X $ gosub out_char X $ gosub out_char X $ gosub out_char X XThe suspend-emacs function in Emacs is redefined to do the equivalent of X $ define/job boss$switch 'f$trnlnm("boss$return_switch","lnm$job")' X $ deassign/job boss$return_switch X ... X XSimilarly boss$return_stuff may be used as the string to stuff into the Xprocess on return. The edit procedure that is called on a TeX error may Xset this to the current TeX command line so that on exiting from the Xeditor the user has the input buffer prepared with the command to re-run XTeX. The user then has the option either of accepting the command (by Xtyping return) or cancelling it (with C-u). X2 Logging XTo save what gets sent to a process in a file, one can use the C-l toggle to Xtoggle creation of a logfile. These files are named BOSSn.LOG (in the Xdirectory where one was at the time of running BOSS, since they are created Xby the BOSS process), where n is the internal BOSS process number (0 to n, Xwhere the number is the process slot; usually this corresponds to the order Xof process creation). Whatever goes to the process as console output is Xlogged, even if BOSS is discarding terminal output from that process; the Xfile output is extracted (as a stream-LF file) prior to the BOSS decisions Xon what to do with the text. A C-e will close the file, and a new C-L or C- Ve Xwill open a new version, and so on. This can be very convenient for Xallowing an editor in another process to look over the log file. XNote that C-L and C-E both toggle logging. The difference is that C-L Xdoes not close the logfile, just suspends output to it, while C-E Xcloses the logfile so that a new version can be created and the version Xjust created can be examined without having to leave BOSS (or exit the Xprocess that was being logged). X2 Redisplay XC-i toggles a buffer capture mode. Its function is to save all output to a Xsession in the BOSS internal buffer (just using it as a circular buffer) Xeven if the output is also going to the terminal. Then upon switching out Xof that session and coming back in, the entire BOSS buffer gets played back. XThe net effect of this is that material that may have scrolled off the Xscreen or been lost due to fullscreen operations of another process gets put Xback, in effect recreating the screen corresponding to the process that had Xits control removed. X XDue to internal logic, the C-i toggle will allow this playback to occur once Xand delete the material, so that what gets saved and played back is what was Xwritten during the current session on the screen. That is, if I have Xprocesses A and B and have process A in C-i mode then a screen session might Xlook (very schematically) like this: X X `091in process A`093 X foo bar X mumble`032 X random messup X editing X random commands X `091Switch to process B`093 X random other messup X `091Switch to process A`093 X foo bar X mumble`032 X random messup X editing X random commands X more stuff typed to process A X and so on X `091Switch to process B`093 X other process B stuff X `091Switch to process A`093 X more stuff typed to process A X and so on X newer still process A commands X XNote that the initial "foo bar" and so on commands were played back only Xonce. X XIf it is desired to keep ALL the text as long as possible, an additional Xmode (which I called "multishot buffering" for no particularly good reason) Xcan be toggled by C-j (linefeed) after the C-\ character. In this mode, all Xof the process A commands that will fit in the BOSS save buffer are kept as Xlong as possible. (Note the BOSS buffer is not really used circularly; text Xis moved up as new text gets added once the buffer fills.) Thus, to buffer Xtext and keep it forever one needs C-i to turn on the buffering AND C-j to Xkeep the text as long as possible. Since the BOSS buffer defaults to 4096 Xcharacters this will generally completely recreate whatever was on screen. X2 Paste XA very limited (and rather kludgey) cut and paste facility exists in that, XIF BOSS is saving output from a process in its buffer (i.e., at least C-i Xmode is active), BOSS can be told to save off the last "n" lines of this Xsaved output from the current process. These are played back into the next Xprocess one switches to as though they had been typed in. Clearly this is Xnot rectangular, allows no editing (unless the lines are pulled into an Xeditor running separately in another process and then pulled to a third Xprocess), and will often not do what one wants. Hokey as it is, though, it Xcould be of some limited value, usually for transferring text to an editor. XThe number of such lines of text is limited by an internal BOSS compile time Xparameter which is in the range of 10 to 20 lines normally; this is to Xprevent unlimited garbage from being transferred and to recognize that the Xtransfer may fail if type-ahead is not sufficient. In general BOSS works Xbetter with large typeahead set in SYSGEN; I have it set to 1024 on our Xsystem, which also aids asynchronous file transfer schemes by avoiding Xcharacter loss. I recommend this also for cases where memory is not too Xtight, to avoid lots of potential synchronization issues with the pty Xdrivers. X2 Broadcasts `032 XWhen running running under BOSS, there is the potential that you will Xreceive multiple copies of the same broadcast. In order to understand what Xis going on, it is useful to distinguish 3 types of broadcast messages: X X(1) Broadcasts to a specific process. E.g., the response of the system to Xcontrol-t. These typically are sent to one of the processes under BOSS. X X(2) Broadcasts to top-level processes. E.g., mail notification. These are Xtypically sent to the process running BOSS and any top-level processes Xunder BOSS. X X(3) Broadcasts to all terminals (including pseudo terminals). E.g., Xshutdown messages. These are typically sent to the process running BOSS and Xall processes under BOSS. X XIn order to help manage broadcast messages, BOSS intercepts any broadcasts Xsent to the process running BOSS, and rebroadcasts them to the current Xprocess. The rebroadcasts are of type USER16. This allows you to shut Xthese rebroadcast out with SET BROAD=NONE or SET BROAD=NOUSER16. Control-s Xalso works to defer broadcasts. Any broadcast handlers which the current Xprocess has active will be called to process the broadcast. X XIn order to avoid getting multiple copies of the same broadcast, here's what Xyou should do: X XIn each subprocess under BOSS, disable type 3 broadcasts, i.e., do X SET BROADCAST=NOSHUTDOWN ! plus others maybe? XYou can accomplish this automatically with the /AUTO_STUFF_STRING qualifier Xto BOSS. X XIn each top-level process, disable type 2 and 3 broadcasts, i.e., do X SET BROADCAST=(NOSHUTDOWN,NOMAIL,NOQUEUE,NOPHONE) ! plus others? XThis assumes that you are logged into the top-level process under the same Xusername. If using a different username, then you wouldn't want to disable Xmost (all?) of the type 2 broadcasts. For example, we would want to permit Xmail notification. X XIn order to stop broadcasts to a particular process, do X SET BROADCAST=NONE X XThere are some drawbacks with way BOSS rebroadcasts messages: X X* There is no way of determining the original type of the broadcast was X(MAIL, PHONE, etc.). For this reason, BOSS rebroadcasts everything as XUSER16. X X* If the rebroadcast fails, because the current process has broadcasts Xdisabled, then there is no way of getting this information to the original Xsender. E.g., if you SET BROAD=NONE is a process under BOSS and someone Xtries to PHONE you, he will not be notified that you're not getting his Xconnection requests. X2 Playback XWith the aid of the /RECORD and /PLAYBACK qualifiers it is possible to let XBOSS replay a session for you. However, this is a crude and rather limited Xfacility. X XIn particular, you should be aware of the following when executing a Xplayback. X XIt's easy for BOSS to overflow the pseudoterminal with data from the record Xfile. This may be expected to happen if you select a high /GEAR value of Xcourse, or if you edit a record file and change the delay specifiers. But Xeven if the system load is a bit higher during playback than it was when the Xsession was recorded, you may get into trouble. X `032 XProblems manifest themselves in several ways: X - BOSS feeds more data to the pseudoterminal than will fit in the typeahea Vd X buffer. In this case you will get DATAOVERUN warning messages on your X terminal, and some characters will be lost. X This problem may perhaps be solved in the future when BOSS learns how X to handle thse overflow conditions properly. X - Commands for BOSS in the record stream may get acted upon before the X current process has completed processing its data. For example, a X process switch may be executed by BOSS, when the current process is X still active processing the data in its typeahead buffer. X - Applications run in one of the processes controlled by BOSS may decide X to throw away typeahead. If the timing is different, this may happen at X another place in the input stream than during recording. X2 New_features X(1.7) Incompatible change: C-\ C-n x required to create a new process. Use XBOSS/SWITCH_CREATE to get the old behavior (where C-\ x would create process XX if it doesn't exist). X X(1.7) C-\ C-t x creates a process at top level. See topic Process_types. X X(1.8) BOSS accepts various qualifiers when it starts. These control the Xcommand character, DCL prompt string, etc. They also can be used to tell XBOSS to start various processes. See topic Qualifiers. X X(1.9) Broadcast messages sent to the process running BOSS are trapped and Xrebroadcast to the current process. See topic Broadcasts. X X(2.0) /DELETE_CHARACTER=num added to allow interchange of some character Xwith delete. See topic /DELETE_CHARACTER. X X(2.1) Logical name BOSS$TERM looked at to determine terminal type. See Xtopic Terminal_types. X X(2.2) BOSS fixed to work with new release of pseudo TTY drivers. X X(2.4) /FLOW_CONTROL added to allow flow control by the top-level process. XSee topic /FLOW_CONTROL. X X(2.5) /PROCESS_DEFAULT=process-type added to get top-level processes Xcreated by default. See topic /PROCESS_DEFAULT X X(2.5) C-\ C-k kills the current process. X X(2.5) BOSS/UW acts as a server for the multi-window Macintosh terminal Xemulator UW. See topic Windows. X X(3.0) File logging (topic Logging), screen redisplay (topic Redisplay), and Xinter-process paste facility (topic Paste) added. These features are due to XGlenn Everhart. X X(3.1) Added record and playback facilities. XQualifiers: X /record`091=filespec`093 default: boss.record X /playback`091=filespec`093 default: boss.record X /gear= is speedup factor for playback; default 1.0 X /lock ignore keyboard input during playback XThe record file will contain the keystrokes from the physical terminal, Xsee the description of these qualifiers. XAdded `094\`094x to request an exit after all processes have terminated. XAdded /quit_on_idle to perform the same function from the command line. XAdded /log to set the default action to logging when creating a process, X and optionally supply a prefix for the log-filename (def:"BOSS"). XDo not close the logfile when logging is stopped, but at quit time. XUse the process name for the log filename iso a number. X `032 X(4.1) Updated for DEC's PTD pseudo TTY drivers. X X(4.2) Added C-e toggle to allow logfiles to be closed when user wants. X`009Fixed wrong lack of setup of log prefix filename. 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 some terminals (Visual 550s in particular) at 9600 baud may Xhave glitches in it. This is because these terminals need flow control Xenabled to operate at 9600 baud, but BOSS doesn't react quickly enough to Xthe control-s sent by the terminal. The solution is to run at 4800 baud or Xslower or to use the FLOW_CONTROL qualifier to BOSS. X XI have seen various strange bugs occurring when using BOSS. These are all Xassociated with VMS running out of some quota. The symptoms range from BOSS Xhanging while creating a process (because LIB$SPAWN does not return) to XSYS$LIBRARY being mis-translated by LINK. As far as I can tell these Xproblems occur only because of the additional stress multiple running jobs Xputs on a users quota's and not because of BOSS problems per se. The Xculprits is usually BYTLM (8000 is too low, 40000 is OK). However PGFLQUO Xis another quota to check. 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 XI know of one program SMP (an algebra system) that grabs the entire PGFLQUO Xon startup. This obviously interfers with BOSS's other processes. The Xsolution is to use a top-level process to run SMP (see topic Process_types). X XPC file transfer using the XMODEM protocol (e.g., with MACX) doesn't work Xthrough BOSS. Kermit seems to work fine. X XAttempting to attach to the process running BOSS from one of its Xsubprocesses causes a hangage. X XControl-\ is used by the Switcher program on the Macintosh. If you are Xrunning your terminal emulation program under Switcher, you need to check X`096Disable keyboard switching' in the Options menu item in Switcher. XAlternatively you can select a different command character with the XCOMMAND_CHARACTER qualifier. X XWhen you run /PLAYBACK, and there is no auto_stuff_string, the first Xcharacter sent to a newly created process is not echoed to your terminal; if Xlogging is active however, the character will show up in the logfile. X2 Windows `032 XIf you are running the UW multi-window Macintosh terminal emulator or the XMeshugena Term Amiga VT200 series terminal emulator, then you can run BOSS Xwith X X $ BOSS/UW X Xand take advantage of a multi-window environment for communicating with the XVAX. (UW stands for Unix Windows.) X XUp to seven processes can be run. Each process is identified by a single Xdigit 1 thru 7. This digit is used in the process name and in the DCL Xprompt. Each process is associated with its own window, named Window #1, Xetc., although the names can be changed within UW. X XBefore you run BOSS/UW, the UW terminal emulator will be operating in Xsingle-window mode. When you start BOSS/UW, this window will close. X XDON'T run BOSS/UW if you're not using the UW software on the Macintosh or Xone of the UW-speaking terminal emulators on the Amiga! X XYou create a window and associated VAX process by selecting New in the XWindows menu. X XYou can select a window by clicking on it (if a portion of it is visible), Xtyping command-1 thru command-7 (for windows 1 thru 7), or by selecting Open Xin the Windows menu. X XYou can close a window by clicking on its close box or by selecting Close in Xthe Windows menu. The associated VAX process remains running. You can view Xthe output at a later time by selecting the window. X XWhen you log out of a process, the window disappears. X XSelecting Shutdown from the File menu causes BOSS to exit and UW to return Xto single window operation. X XFinally, UW also supports Option as a Meta key and high-level mouse support. XBoth these are useful in Emacs. See subtopic Emacs. X XWARNING: UW is a less capable terminal emulator than VersaTerm. Don't Xexpect too much of it! It does however support multiple windows to Xdifferent processes; the lack of this in VersaTerm is its principle defect. X3 Configuration XRead the MacWrite documentation on UW for more information. X XIn UW you can set both the default Window configuration used when a new Xprocess is created (Configure menu) and the configuration of the active Xwindow (Settings in the Window menu). X XI suggest the following default configuration: X X (a) Serial Port: set Flow control on X (b) Protocol: set to "Original UW protocol" X (c) Keyboard: set "META key" X (d) Window Defaults: set "ANSI" X (d') Set TTY Defaults: set "Mouse Action" to "Clipboard" X XSave this configuration as uw.conf. (Then you don't need to repeat it each Xtime you start up.) X3 UW_availability XUW is available in the area at SUMEX.STANFORD.EDU. It's in XUnix shar format in files UNIX-UW-42-PART%.SHAR (PART1 thru PART8). X XAt a minimum you need the UW terminal emulator and (if you have Emacs Xusers) MACMOUSE.EL. X XAt PPL, the terminal emulator and documentation are in X MAC$:`091NEW`093UNIX-UW-42.HQX X(in BinHex format). MACMOUSE.EL is in the default library area for Emacs, XEMACS_LIBRARY:`091LISP`093. X3 Emacs XIn order to run Gnu Emacs under UW, you need to set you Emacs terminal Xtype to "uw", with e.g., X $ setup emacs uw X XThe option key acts as a Meta-shift. Thus Option-F is the same as ESC F X(i.e., goes forward a word). X XYou should set UW to transmit the location of Mouse clicks to the VAX (in XConfigure TTY under Settings in the Window menu). This gets the mouse Xclick transmitted to the VAX for this window only. To get Emacs to Xunderstand what UW sends, insert X X (global-set-key "\em" 'move-mac-cursor) X (autoload 'move-mac-cursor "macmouse" nil t) X Xinto your Emacs init file (sys$login:.emacs). X XHere's what happens with mouse clicks: X X Up or down mouse button in a window selects that window X X A scroll bar/thumbing area for each window with the following features: X the mode lines are horizontal scroll bars X (running from rightmost column to under leftmost column) X the unused right window bar and the dividing lines between X windows are vertical scroll bars X (running from top of window THRU modeline X for vertical scroll bars: X click at line 1 does previous page X click at last line does next page X click anywhere else "thumbs" to the relative portion of the buffer. X shift-click at line 1 scrolls one line down X shift-click at last line scrolls one line up X shift-click elsewhere moves line to top of window X option-shift-click elsewhere moves line to bottom of window X for horizontal scroll bars: X click at column 1 does scroll right one window width X click at last column does scroll left one window width X click anywhere else moves to that "percent" of the buffer width X shift-click at column 1 scrolls one column right X shift-click at last column scrolls one column left X shift-click elsewhere moves column to right of window X option-shift-click elsewhere moves column to left of window X XThere is also basic positioning and kill-buffer support: X click in a buffer moves dot there and selects that buffer X drag copies the dragged region to the kill buffer X shift-drag deletes the dragged region to the kill buffer X X It is possible to use the scrolling and thumbing area to make the region X larger than a single screen; just click, scroll, release. Make sure X that the last scroll is just a down event; the up must be in the buffer. X The last mouse position is remembered for each different buffer (not X window), and thus you can start a drag in one buffer, select another, X go back to the first buffer, etc. X X option-click yanks from the kill buffer X option-shift-click similarly yanks from a named buffer. X3 Other_features XMost of the capabilities of BOSS in its regular mode are available. XHowever, there are some differences in BOSS/UW X XOnly 7 processes can be run (instead of 8). X XThe processes are named 1 thru 7 not A thru Z. X +-+-+-+-+-+-+-+- END OF PART 2 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+ XBOSS/FLOW_CONTROL is used to be set (independent of what you actually ask Xfor). Note that under UW the use of flow control by the Macintosh Xhardware to prevent data overruns of the Mac's buffers is carried out Xindependently of your attempts to control output with C-s and C-q. In Xparticular, C-s and C-q can be used for their regular functions in Emacs, Xeven though the Macintosh and the VAX are still using flow control. X XBOSS/UW sets the default output flag to p (instead of b). This allows Xoutput from all processes to be sent to their respective windows. This Xdefault be overridden with DEFAULT_OUTPUT_FLAG qualifier. And of course Xyou can use C-\ C-b, etc., to set this flag on a per-process basis. X XBOSS/NOCOMMAND_CHARACTER can be used to indicate that no command character Xis to be used. (Thus all characters you type get seen by your VAX Xprocess.) By default, C-\ is still used as a command character. X XBOSS doesn't print "`091Switch to process 5...`093" messages, since the Xswitching is obvious from the arrangement of windows. Other messages X(e.g., the response to C-\ ? should appear in the active window). X XC-\ 3 will tell BOSS to switch to process 3, but UW won't bring that Xwindow to the front. The same comment applies to process-initiated Xswitches (via the BOSS$SWITCH logical name. You should probably use one Xof the other methods for switching processes (clicking on the window, Xcommand-3, etc.) X XBOSS/PROCESS_DEFAULT=TOP will cause BOSS's processes to be top-level Xprocesses. Thus when you select New in the Windows menu, you will see a XUsername: prompt. X XYou can create processes with C-\ C-n 4 or C-\ C-t 4 (for subprocesses and Xtop-level processes). This allows you to create either type of process, Xwhile selecting New in the Windows menu produces only a process of the Xdefault type (governed by BOSS/PROCESS_DEFAULT). X XBOSS/START=(1,2)/STUFF=Emacs will create processes 1 and 2 and start Emacs Xin process 1. This is just the same as BOSS behavior in its regular mode. X3 Misfeatures XOccasionally BOSS loses track of what UW thinks is the active window. XYour typed input will then be sent to the wrong process. This is Xcorrected by switching to some other window (e.g., by clicking on it) and Xthen switching back to the original window. X XOther than the fact that UW supports multiple windows and more intelligent Xmouse behavior with Emacs, UW is a much worse terminal emulator than XVersaTerm. In particular: X X* It doesn't save what scrolls off the screen. X X* I haven't been able to get EVE or LSE to work reasonably. I presume X there's some way of telling these programs what UW can do (via X TERMTABLE); I just haven't managed to get it to work right. Emacs X works just fine though. X X* Keypad is not supported. X X* Arrow keys don't work. X X* UW implements a Tektronix 4010 emulation, but it's a pretty miserable X affair. X X* Can't print. X X* Can't do file transfers. X XI've only implemented the most basic level of UW service under BOSS. The Xnext level allows windows to be retitled from the VAX, as well as setting Xmany of the other attributes of windows. This will most likely not get Ximplemented. X XThe main reason for implementing the UW features in BOSS was to show that Xthe Macintosh can provide a multi-window enviroment for the VAXes. Now we Xhave to get Lonnie Abelbeck to modify VersaTerm to support the UW Xprotocol... X2 Acknowledgements XBOSS was written by Charles Karney based on the PHOTO program written by XAsbed Bedrossian of USC. It utilizes the Pseudo TTY package of Dale Moore Xof CMU and Kevin Carosso of Network Research Co. File logging, screen Xredisplay, and inter-process paste were added by Glenn Everhart X(EVERHART@ARISIA.dnet.ge.com). Record and playback were added by Henk XDavids (hdavids@mswe.dnet.ms.philips.nl). PTD support was added by Steve XAlpert (sra@idx.com). X XUW, the multi-window Macintosh terminal emulator was written by John D. XBruner of LLNL. The Emacs mouse support was written by Gregory S. Lauer of XBBN. X XBugs, questions, etc. to X Charles Karney X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2662 $ CALL UNPACK BOSS.HLP;97 992677057 $ create/nolog 'f' X/* BOSS interactive job controller. XCopyright (c) 1987, 1988 by Charles Karney. All rights reserved. X XWritten by X Charles Karney X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2662 X XBOSS 3.0 features added by Glenn Everhart (EVERHART@ARISIA.dnet.ge.com). X XBased on the PHOTO program of Asbed Bedrossian (USC, asbed@oberon.usc.edu). X XIt utilizes the Pseudo TTY package of Dale Moore (CMU, XDale.Moore@PS1.CS.CMU.EDU) and Kevin Carosso (Network Research Co., Xkvc@nrc.com, kvc@ymir.bitnet). X XThe UW terminal emulator was written by John Bruner (LLNL, Xjbd@mordor.s1.gov). He also defined the UW protocol. X XDESCRIPTION: X XBOSS lets you create up to 8 processes on a VAX/VMS system. Each process Xis identified by a single letter (A thru Z). At most one of these Xprocesses is `096current'. What you type is sent to that process, and outpu Vt Xfrom that process is sent to your terminal. A process which is not current Xcan run but cannot do output. (Output is saved until you make that process Xcurrent.) You usually switch between processes by typing control-\ Xfollowed by the identifying letter. X XYou can run any program under BOSS. For example, you might X run Emacs or EVE in process E X SET HOST to another machine in process H 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 XAs an experimental addition, BOSS can also be run with the UW multiple- Xwindow terminal emulator for the Macintosh or Meshugena-term on Amiga. XIn this case you interact with the various processes through their own Xwindows. X XINSTALLATION: X XCompile and link with X $ @boss_build XInstall with X $ @boss_install ! 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. (The DECWindows drivers Xin VMS 5.3 work just fine.) X XBOSS can be operated without installing it with privileges (but you will Xstill need the pseudo TTYs installed). If BOSS doesn't have 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 us Ved 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 suppor Vt. X C-k command added to kill current process. XVersion 2.6. September 26, 1988 X Write out stuffed strings one character at a time to prevent part of the X string being lost. (A better solution would be to handle the DATA_OVERRUN X condition properly by waiting for an XON AST.) X Fixed bug where the y/n response to process deletion and exiting was X interpreted as a process switch command if the current process completed X in the meantime. X Add /AUTO_STUFF_STRING XVersion 2.7. November 4, 1988 X Ignore error status 0. X Fix C-k so it doesn't try to kill top-level process. XVersion 2.7b 8/22/1990 Glenn Everhart X Added control-I toggle for buffering. Allows buffering of console X output even from active output so one can switch to another window X and get back the buffered text. Switching processes resets. Will X arrange so that some "scrolled off" text can be saved, though the X buffering is switched off on process switches. Another toggle will X be added to allow buffer display to be a one-shot without losing old X contents. XVersion 2.7c 8/23/90 Glenn Everhart X Add C-L toggle to open or close output to BOSSx.LOG for current X process. Make it apply per process. Shutdown will close the file X where orderly. XVersion 2.7d 8/30/90 Glenn Everhart X Add C-G to grab 1 to 9 lines out of one process' buffer (assuming X data is being buffered) and shove it into the next process where X one starts it, similar to boss_stuff operation. Kludgey but possibly X useful. XVersion 2.8. June 23, 1989 X Set /noescape on terminal running BOSS to avoid "partial escape" error XVersion 2.9. August 1, 1989 X Fix error in C-\ C-h documentation. XVersion 3.0. May 31, 1991 X Merge C. Karney mods for V2.9 into Glenn Everhart version 2.7d+ XVersion 3.1. December 12, 1991 Henk Davids X Source processed by "indent -ncdb -di0 -i4 -nfc1 -br -ce -psl -ip -cli1". X Added poor mans record and playback facilities. X Qualifiers: X /record`091=filespec`093 default: boss.record X /playback`091=filespec`093 default: boss.record X /gear= is speedup factor for playback; default 1.0. X if is "I`091nfinite`093" we will skip delays. X /lock ignore keyboard input during playback X The record file will contain the keystrokes from the physical terminal, X interspersed with delay specifications of the form \, X where is the delay in 100 millisecond units. X Added C-x command to request an exit after all processes have terminated. X Added /quit_on_idle to perform the same function from the command line. X Added /log to set the default action to logging when creating a process, X and optionally supply a prefix for the log-filename (def:"BOSS"). X Do not close the logfile when logging is stopped, but at quit time. X Use the process name for the log filename iso a number. XVersion 4.0 March 6,1992 Steve Alpert (sra@idx.com) X Add PTD hooks (for vms 5.4-3++) (update to 3.0 XVersion 4.1 Merge 4.0 changes into version 3.1 (karney@princeton.edu) XVersion 4.1a GCE 4/1992 - Add ctrol-V to close logfile (or open if not X`009present). This allows small logfiles to be created and used X`009from other processes without exiting BOSS. XVersion 4.2 - Fix some problems with BOSS-STUFF with PTD routines by X`009using the single character kludge-o solution that works with X`009PY/TWdrivers. XVersion 4.2a - 19-MAY-1992, Kenn Humborg (elehumborg@orbsen.ucg.ie) X`009Fix things so that if the call to LIB$GET_VM_PAGE returns with X`009"insufficient virtual memory" we just say so nicely rather than X`009exiting the program and killing _all_ the BOSS processes currently X`009running. XVersion 4.3 - 6/1992, Glenn C. Everhart. Added command mode processing X`009started by `094\+ (plus char after the control char). The mode is X`009to accept ONE command line which will be structured as X`009verb args X`009which will let the verb determine what will be done with the X`009args. The command line is terminated by return. The command X`009processing is intended for setup purposes mainly, as it will X`009not strive to keep ASTs going and may cause some I/O to X`009overrun if there's a lot going on or the user is too slow. X`009However the state machine is getting VERY complex! Initial commands X`009understood are S, which sets switch chars to the string X`009"chars" (no brackets in cmd, mind). These are set at each X`009context switch after stuff_chars. E.g. S`094W where `094W is control-W X`009would cause BOSS to emit control-W every time it switched to X`009this process. G does the same for all processes (Global X`009set). There may be up to 7 characters preloaded in this way. X`009Also understood are commands Pnumber and Anumber. Pnumber limits X`009playback of saved information in `094I`094J mode to "number" characters, X`009forced between 100 and BUFSIZE limits, for the current process. X`009Anumber limits this playback for all processes to number. Note X`009that normal buffered mode output is unaffected by this and will X`009allow dump of the whole saved buffer; this is intended to handle X`009the case where everything is being saved past where it would X`009normally be and limit the amount of that which gets played back X`009at every context change. XVersion 4.3a Bug fix by Jerry Leichter XVersion 4.4 From sra@idx.com X`009These are changes to BOSS.C (any version) to minimize the UW window X`009switching. The P1_IAC, P1_FN_OSELW sequence needs to be given only X`009when the output window changes. These modifications eliminate the X`009excessive I/O. XVersion 4.5 From sra@idx.com X`009When a pseudo-terminal goes away, a LIB$FREE_VM_PAGE should be done X`009to reclaim the virtual space associated with that terminal. If this X`009is not done, the space isn't reused and boss may fail to init X`009subprocesses! XVersion 4.6 From elehumborg@orbsen.ucg.ie X`009Fix bug in call to PTD$CREATE... XVersion 4.7 From raxco!galaxy.dnet!gleeve@uunet.uu.net and sra@idx.com X`009Fix to bug fix in call to PTD$CREATE... X 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-a append to log file? (somewhat obsolete; also conflicts with kermit) X Add support for VT420 terminals, where the display buffer can be larger X than the screen. X Add some minimal 'expect' support in playback mode. Somebody care to X port Don Libes' 'expect' package to VMS? X*/ X X#define VERSION`009`009"4.7" X X/* Define the following for VMS 5.4-3++ pseudo terminals */ X#define USE_PTD 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 TIME X#include DVIDEF X#include PERROR X#include FILE X#include ERRNO X#include LIBDEF X X#include STDIO X#include STDLIB X#include CLIMSGDEF X X/* ----- Constants ----- */ 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`009/* can't exceed 512 for PTD's */ 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`009/* Number of process allowed */ X#define NALPHMAX 26`009/* Number of possible names */ X X#define bad(j) !((j) & 1) X#define check(a) if (bad(st = (a))) \ X `123if (st != 0) LIB$SIGNAL(st);`125 else `123`12 V5 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#define CUTP 6 X X#define BRK$C_DEVICE 1 X#define BRK$C_USER16 47 X X/* X * uw protocol X * X * Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission V 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 P1_IAC 0001`009/* interpret as command */ X#define P1_DIR 0100`009/* command direction: */ X#define P1_DIR_HTOM 0000`009/* from host to Mac */ X#define P1_DIR_MTOH 0100`009/* from Mac to host */ X#define P1_FN 0070`009/* function code: */ X#define P1_FN_NEWW 0000`009/* new window */ X#define P1_FN_KILLW 0010`009/* kill (delete) window */ X#define P1_FN_ISELW 0020`009/* select window for input */ X#define P1_FN_OSELW 0030`009/* select window for output */ X#define P1_FN_META 0050`009/* add meta to next data char */ X#define P1_FN_CTLCH 0060`009/* low 3 bits specify char */ X#define P1_FN_MAINT 0070`009/* maintenance functions */ X#define P1_WINDOW 0007`009/* window number mask */ X#define P1_CC 0007`009/* control character specifier: */ X#define P1_CC_IAC 1`009/* IAC */ X#define P1_CC_XON 2`009/* XON */ X#define P1_CC_XOFF 3`009/* XOFF */ X#define P1_MF 0007`009/* maintenance functions: */ X#define P1_MF_ENTRY 0`009/* beginning execution */ X#define P1_MF_ASKPCL 2`009/* request protocol negotiation */ X#define P1_MF_CANPCL 3`009/* suggest protocol */ X#define P1_MF_SETPCL 4`009/* set current protocol */ X#define P1_MF_EXIT 7`009/* execution terminating */ X#define P1_NWINDOW 7`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 X/* Definitions for record/playback modes */ X/* To start a delay specifier in the record file: */ X#define DELAY_ESC '\\' X/* Less than this many secs, and we will consider keystrokes as consecutive: V */ X#define DELAY_THR 0.3 X/* End definitions for record/playback modes */ X Xstruct CHARBLK `123 X unsigned char class, ttype; X unsigned short pgwid; X unsigned ttchr:24; X unsigned char pglen; X unsigned int xchar; X`125; X Xstruct IOSBBLK `123 X unsigned short stats, tmoff, tmntr, tmsiz; X`125; X Xtypedef struct DVIBLK `123 X unsigned short len, code; X char *buffp; X long *lenp; X long terminate; X`125 DVIBLK; X Xint X py_chn`091NPROCMAX`093, py_mb_chn`091NPROCMAX`093, tt_chn, tt_mb_chn, pi Vd`091NPROCMAX`093, X st, cur, kill_proc, count`091NPROCMAX`093, buflen`091NPROCMAX`093, procn Vo`091NALPHMAX`093, X priv`0912`093, privs`0912`093, def_stuff_len, bufmod`091NPROCMAX`093, bu Vfmod2`091NPROCMAX`093, X logmod`091NPROCMAX`093, cutpas`091NPROCMAX`093, kprc, no_phy_io, no_oper V, brkthru, X ctlchar, init, nproc, nalph, recording, record_fd, playback, playback_fd V, X quit_in_progress = FALSE, keyboard_locked = FALSE, synchr_quit = FALSE, X auto_log = FALSE, log_file_prefix_len; X Xfloat gear = 1.0;`009`009/* for playback */ X Xint logfd`091NPROCMAX`093; X Xstatic char X *clr, *bos, *ceol, *ceoln, *retval, ctlchar_str`0914`093, prompt_begin`0 V9130`093, X prompt_end`09130`093, switch_create, flow_control, delete_char, stuff_b Vuf`091256`093, X def_stuff_buf`091256`093, buf`091256`093, image`091IMAGELEN`093, finalt Vp`091NPROCMAX`093`091TPDEVLEN`093, py_mb`091NPROCMAX`093`091MBSIZ`093, X tt_mb`091TTMBSIZ`093, buffer`091NPROCMAX`093`091BUFSIZE`093, term_buf`0 V91MAXBUF`093, blocked`091NPROCMAX`093, X mode`091NPROCMAX`093, pmode`091NPROCMAX`093, defmode, defproc, name`091 VNPROCMAX`093, X py_post`091NPROCMAX`093, proc_type`091NPROCMAX`093, enable_hangup`091NP VROCMAX`093, input_state = NORMAL, X oboss_id = 0, super_ac_mode = PSL$C_SUPER, uw = 0, uw_state = UW_NORMAL V, X uw_meta = 0, first_name, last_name, mac_command = 0, record_file`091256 V`093, X playback_file`091256`093, log_file_prefix`09180`093; X/* Add a command buffer for a command mode to let us joggle more stuff w/o X a super complex state machine. Just handle with normal reads/writes and X accept possible lossage of ast speed etc. if we take too long. */ Xstatic char emitchr`091NPROCMAX`093`0918`093; Xint emitlen`091NPROCMAX`093; X/* echlen is length of buffer to dump out in `094I `094J mode */ Xint echlen`091NPROCMAX`093,echnew`091NPROCMAX`093; Xstatic char cmdlin`091128`093; Xstatic char uwLastWin = 0xff;`009/* minimize window switching */ Xstatic unsigned char input_char; Xstatic char X#ifdef USE_PTD X *tpline`091NPROCMAX`093,`009`009/* filled in later */ X *otpline`091NPROCMAX`093; X#else X tpline`091NPROCMAX`093`091LINESZ`093; X#endif X Xextern int close(); Xextern int creat(); Xextern int write(); X Xextern int BOSS_CLD(); X Xstruct CHARBLK tt_chr, tt_sav_chr; Xstruct IOSBBLK tiosb, tiosbmb, piosb`091NPROCMAX`093, miosb`091NPROCMAX`093; X Xstatic short trnlnm_string_len; Xstatic char trnlnm_string`091BUFSIZE + 151`093; X/* Make this string quite long so we can use it for cut/paste */ X/* n.b. cut/paste a bit kludgey at the moment */ X Xstruct ITEM_LST `123 X unsigned short len, code; X char *addr; X short *retlen; X`125 trnlnm_item = `123 X 80, LNM$_STRING, &trnlnm_string, &trnlnm_string_len X`125; X X/*---- timer functions ---*/ X X/* static timer memory */ Xstatic double last_timestamp = 0.0; X Xstatic double Xtime_so_far() X`123 X timeb_t tms; X X ftime(&tms);`009`009/* get time in millisec units */ X /* resolution is 10 msecs */ X return ((((double) tms.time * 1000.0) + (double) tms.millitm) / 1000.0); X`125 X Xvoid Xstartclock() X`123 X last_timestamp = time_so_far(); X`125 X Xdouble Xelapsedtime() X`123 X return (time_so_far() - last_timestamp); X`125 X Xvoid Xmsleep(millisecs)`009`009/* Hibernate n milliseconds */ X int millisecs; X`123 X int i, sleep; X extern int sys$schdwk();`009/* scheduled wake-up */ X extern int sys$hiber();`009/* hibernate */ X extern int sys$canwak(); X extern int lib$mult_delta_time(); X int delta`0912`093 = `123-10000, -1`125;/* delta 1 millisec in quadword V */ X X if (millisecs <= 0) X`009return; X /* convert millisecs value to delta time in system quad time format */ X i = lib$mult_delta_time(&millisecs, delta); X X check(sys$schdwk(0, 0, delta, 0)); X check(sys$hiber());`009`009/* sleep */ X check(sys$canwak(0, 0));`009/* cancel schdwk request */ X return; X`125 X Xquit() X`123`009`009`009`009/* This is done upon exiting, by exit handler */ X int i, j; X char id`0912`093; X X#ifdef USE_PTD X unsigned long blk,adr; X#endif X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_id, id); X X if (uw && !mac_command) X`009uw_fun(P1_FN_MAINT `124 P1_MF_EXIT, 0, 0); X X if (oboss_id != 0) `123`009/* Restore BOSS$ID */ X`009id`0910`093 = oboss_id; X`009j = LIB$SET_LOGICAL(&d_boss_id, &d_id, 0, 0, 0); X `125 X for (i = 0; i < nproc; i++) `123 X`009if (name`091i`093) `123 X#ifndef USE_PTD X`009 j = SYS$DELMBX(py_mb_chn`091i`093); X`009 if (bad(j)) X`009 printf("`091SYS$DELMBX pseudo-mbx deletion failed`093\n"); X#else X`009 j = PTD$DELETE(py_chn`091i`093); X`009 if (bad(j)) X`009 printf("`091PTD$DELETE pseudo-terminal deletion failed`093\n"); X#endif X`009 /* Last chance close all log files */ X`009 if (logfd`091i`093 != 0) X`009`009j = close(logfd`091i`093); X`009`125 X `125 X quit_in_progress = TRUE; X j = SYS$CANCEL(tt_chn);`009/* Cancel outstanding input request physical X`009`009`009`009 * terminal */ X j = SYS$QIOW(0, tt_chn, IO$_SETMODE, 0, 0, 0, &tt_sav_chr, TTCHRLEN, 0, V 0, 0, 0); X if (bad(j)) X`009printf("`091SYS$QIO /setmode/ failed`093\n"); X if (recording) `123 X`009j = close(record_fd); X `125 X printf("\nEnd BOSS\n"); X`125 X X#ifndef USE_PTD Xmb_srv(n)`009`009`009/* AST for mailbox message on top-level */ X`009`009`009`009/* process completion */ X int n; X`123 X if (proc_type`091n`093 == TOP) `123 X`009if (enable_hangup`091n`093) X`009 comp_srv(n); X`009else `123 X`009 enable_hangup`091n`093 = 1; X`009 check(SYS$QIO(0, py_mb_chn`091n`093, IO$_READVBLK, &miosb`091n`093, V &mb_srv, n, X`009`009`009 &py_mb`091n`093, MBSIZ, 0, 0, 0, 0)); X`009`125 X `125 X`125 X#endif X X/* get termination notice from PTD if in PTD mode */ Xcomp_srv(n)`009`009`009/* AST for completion of processes */ X int n; X`123 X int j; X X#ifdef USE_PTD X unsigned long blk,adr; X/* free virtual memory */ X blk = 4 * 512;`009`009/* 2 plus 2 guard pages */ X adr = tpline`091n`093-516;`009/* original inadr`0910`093 */ +-+-+-+-+-+-+-+- END OF PART 3 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 4 -+-+-+-+-+-+-+-+ X j = LIB$FREE_VM_PAGE(&blk,&adr); X if( bad(j)) X printf("`091LIB$FREE_VM_PAGE failed\n"); X#else X j = SYS$DELMBX(py_mb_chn`091n`093); X if( bad(j)) X printf("`091SYS$DELMBX failed\n"); X#endif X if (name`091n`093) X`009procno`091name`091n`093 - first_name`093 = -1; X name`091n`093 = '\0'; X if (uw && !mac_command) X`009uw_fun(P1_FN_KILLW `124 ((n + 1) & P1_WINDOW), 0, 0); X if (kill_proc == n) X`009kill_proc = -1; X if (logfd`091n`093 != 0) X`009j = close(logfd`091n`093); X if (cur == n) X`009cur = -1; X if (synchr_quit && !count_processes()) `123 X`009/* No more processes, and synchr quit requested: exit */ X`009exit(SS$_NORMAL); X `125 X`125 X X/* X Output routines for pseudo terminal X*/ X/* Note: as coded, these routines try to use the XON-AST mechanism to X`009 prevent overflowing the PY with data in playback mode. X`009 However, although the basic mechanism seems to work on the X`009 PY side: X`009 `009start output X`009 `009hibernate X`009`009in the IO AST, check the status: X`009`009`009success, then wake X`009`009`009data overrun, then schedule XON AST X`009`009in the XON AST, restart output if needed X`009`009else wake. X`009we still will get data overrun errors, but now in the read X`009from TW in the subprocess. X`009What am I doing wrong here? X*/ X X/* Request codes */ X#define SET_XON_AST`0091 X#define SET_XOFF_AST`0092 X#define SET_LINE_AST`0093 X X/* Static buffers */ X/* Since only one PY is used at any time for output, we only need 1 copy */ Xstatic unsigned char py_out_buf`09180`093; /* only 1 char used currently */ Xstatic unsigned char *py_out_buf_ptr; Xstatic int py_out_len = 0; Xstatic struct IOSBBLK py_out_iosb; X X/* X AST for py XON notifcation X*/ Xvoid Xpy_out_xon() X`123 X void py_out_srv(); X if (py_out_len) `123 X`009check(SYS$QIO(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, X`009`009 py_out_srv, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X `125 else `123 X`009check(sys$wake(0, 0)); X `125 X`125 X X/* X AST for py output completion X*/ Xvoid Xpy_out_srv() X`123 X if (py_out_iosb.stats != SS$_DATAOVERUN) `123 X`009check(py_out_iosb.stats); X`009py_out_len = 0; X`009check(sys$wake(0, 0)); X `125 else `123 X`009/* update output len and ptr */ X`009py_out_len -= py_out_iosb.tmoff; X`009py_out_buf_ptr += py_out_iosb.tmoff; X`009/* schedule an XON AST */ X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_SETMODE, 0, X`009`009 py_out_xon, 0, 0, 0, 0, SET_XON_AST, 0, 0)); X `125 X`125 X X/* X Send data to current pseudo terminal. X If we are not on_AST_level let's try to be careful not to overflow X the pseudo terminal. X Otherwise, just use the old method (QIOW) for now. X*/ Xvoid Xto_pty(on_AST_level, character) X int on_AST_level; X unsigned char character; X`123 X py_out_len = 1; X py_out_buf_ptr = &py_out_buf`0910`093; X *py_out_buf_ptr = character; X if (on_AST_level) `123 X#ifndef USE_PTD X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, 0, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X`009if (py_out_iosb.stats != SS$_DATAOVERUN) X`009 check(py_out_iosb.stats); X#else X`009otpline`091cur`093`0910`093 = character; X/* should buffer this! */ X`009check(PTD$WRITE(py_chn`091cur`093, 0, 0, otpline`091cur`093-4, py_out_le Vn, 0, 0)); X#endif X `125 else `123 X`009py_out_iosb.tmoff = 0; X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, X`009`009 py_out_srv, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X#else X`009otpline`091cur`093`0910`093 = character; X`009check(PTD$WRITE(py_chn`091cur`093, py_out_srv, 0, otpline`091cur`093-4, V py_out_len, 0, 0)); X#endif X`009check(sys$hiber()); X `125 X`125 X Xint Xlow_lib_spawn(n, pty_io, pid, name) X /* Spawns subprocess to speak to pseudo terminal */ X char *pty_io, name; X int n, *pid; X`123 X int flg = 1, len, val, i; X char proc`09120`093, prompt`09150`093, id`0912`093; X $DESCRIPTOR(d_pty_io, pty_io);`009/* PTY name + number */ X $DESCRIPTOR(d_proc, proc);`009`009/* Process name */ X $DESCRIPTOR(d_prompt, prompt);`009/* Prompt */ X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_id, id);`009/* The id */ X d_pty_io.dsc$w_length = strlen(pty_io); X strcpy(proc, getenv("TT")); X len = strlen(proc); X if (proc`091len - 1`093 == ':') X`009proc`091--len`093 = '\0'; X strcat(proc, "_A"); X len = strlen(proc); X proc`091len - 1`093 = name; X d_proc.dsc$w_length = len; X if (proc`0910`093 == '_') `123 X`009d_proc.dsc$w_length--; X`009d_proc.dsc$a_pointer++; X `125 X sprintf(prompt, "%s%c%s", prompt_begin, name, prompt_end); X d_prompt.dsc$w_length = strlen(prompt); X id`0910`093 = 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`009`009 &comp_srv, n, &d_prompt, 0); X if (!bad(val)) X#ifndef USE_PTD X for (i = 0; i < def_stuff_len; i++) `123 X`009check(SYS$QIOW(0, py_chn`091n`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 def_stuff_buf + i, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X `123 X for (i = 0; i < def_stuff_len; i++) `123 X`009otpline`091n`093`0910`093 = def_stuff_buf`091i`093; X/*`009strncpy(otpline`091n`093, def_stuff_buf, def_stuff_len); */ X`009PTD$WRITE(py_chn`091n`093, 0, 0, otpline`091n`093 - 4, 1, 0, 0); X/* check for completion! */ X `125 X `125 X#endif X check(LIB$DELETE_LOGICAL(&d_boss_id, 0)); X return (val); X`125 X Xpy_srv(n)`009`009`009/* AST reads on pseudo terminal */ X int n; X`123 X int j, kkkk; X char *tpptr; X py_post`091n`093 = 0; X#ifndef USE_PTD X check(piosb`091n`093.stats);`009/* Check status */ X count`091n`093 = piosb`091n`093.tmoff + piosb`091n`093.tmsiz; /* How muc Vh was read */ X#else X check(*(short*)(tpline`091n`093-4));`009/* status block! */ X count`091n`093 = *(short*)(tpline`091n`093-2); X#endif X X if (n >= 0 && logmod`091n`093 != 0) `123 X`009if (logfd`091n`093 != 0) `123 X`009 tpptr = tpline`091n`093; X`009 /* write text to active logfile if one exists */ X`009 j = write(logfd`091n`093, tpptr, count`091n`093); X`009`125 X `125 X if (n == cur `124`124 mode`091n`093 == 'p') `123 X`009if (bufmod`091n`093 != 0) `123`009/* Switch buffering separately */ X`009 if (count`091n`093 + buflen`091n`093 < BUFSIZE) `123 X`009`009for (j = 0; j < count`091n`093; j++) X`009`009 buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j` V093; X`009 `125 else `123 X`009`009/* copy buffer down and add in new text */ X`009`009/* First copy text down enough to hold the new line */ X`009`009kkkk = buflen`091n`093 - count`091n`093; X`009`009if (kkkk <= 0) X`009`009 kkkk = 1; X`009`009for (j = 0; j < kkkk; j++) X`009`009 buffer`091n`093`091j`093 = buffer`091n`093`091j + count`091n`093 V`093; X`009`009buflen`091n`093 = buflen`091n`093 - count`091n`093; X`009`009/* Now add the new text after the line */ X`009`009for (j = 0; j < count`091n`093; j++) X`009`009 buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j` V093; X`009 `125 X`009`125`009`009`009/* bufmod */ X`009term_out(n);`009`009/* Write the stuff to the terminal */ X `125 else if (mode`091n`093 == 'w') `123 X`009blocked`091n`093 = 1; X `125 else if (mode`091n`093 == 'o') `123 X`009blocked`091n`093 = 1; X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4, LINESZ V-4)); X#endif X`009py_post`091n`093 = 1; X `125 else if (mode`091n`093 == 'b') `123 X`009if (count`091n`093 + buflen`091n`093 < BUFSIZE) `123 X`009 for (j = 0; j < count`091n`093; j++) X`009`009buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j`093; X#ifndef USE_PTD X`009 check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py V_srv, n, X`009`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009 check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LI VNESZ-4)); X#endif X`009 py_post`091n`093 = 1; X`009 blocked`091n`093 = 0; X`009`125 else `123 X`009 py_post`091n`093 = 0; X`009 blocked`091n`093 = 1; X`009`125 X `125 X`125 X Xto_term(buf, len, chan) X char *buf; X int len, chan; X`123 X int i, j; X char ochar; X X if (!uw) `123 X`009j = 0; X`009while (j < len) `123 X`009 check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009 `009`009 0, 0, &buf`091j`093, X`009`009`009 (len - j < MAXBUF) ? len - j : MAXBUF, X`009`009`009 0, 0, 0, 0)); X`009 j += MAXBUF; X`009`125 X `125 else if (chan >= 0) `123 X`009j = 0; X`009i = 0; X`009if( chan != uwLastWin ) `123 /* changed windows? */ X`009 term_buf`091i++`093 = P1_IAC; X`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_OSELW `124 ((chan + 1) & V P1_WINDOW); X`009 uwLastWin = chan; X`009`125 X`009while (j < len) `123 X`009 ochar = buf`091j++`093; X`009 if (ochar & 0200) `123 X`009`009term_buf`091i++`093 = P1_IAC; X`009`009term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_META; X`009`009ochar = ochar & 0177; X`009 `125 X`009 switch (ochar) `123 X`009`009case P1_IAC: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_IA VC; X`009`009 break; X`009`009case XON: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_XO VN; X`009`009 break; X`009`009case XOFF: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_XO VFF; X`009`009 break; X`009`009default: X`009`009 term_buf`091i++`093 = ochar; X`009`009 break; X`009 `125 X`009 if (i > MAXBUF - 4) `123`009/* If no room for another meta-xon */ X`009`009check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009`009`009 0, 0, term_buf, i, 0, 0, 0, 0)); X`009`009i = 0;`009`009/* Leave OSELW command in first 2 bytes */ X`009 `125 X`009`125 X`009if (i) `123`009`009/* Spit out rest of buffer */ X`009 check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009 `009`009 0, 0, term_buf, i, 0, 0, 0, 0)); X`009 i = 0; X`009`125 X `125 X`125 X Xterm_out(n) X int n; X`123 X int j, k, kk, kkk, kkkk; X char nname; X char *tpptr; X $DESCRIPTOR(d_boss_switch, "BOSS$SWITCH"); X $DESCRIPTOR(d_boss_stuff, "BOSS$STUFF"); X $DESCRIPTOR(d_lnm_job, "LNM$JOB"); X tpptr = tpline`091n`093; X X if (buflen`091n`093 > 0) `123 X`009/* If buffering current stuff and in a print mode, print only new X`009 * stuff. Thus only print it all if bufmod == 0. */ X`009if (bufmod`091n`093 == 0) `123 X/* Where this process is not in `094i`094j mode and it was buffering data, X echnew will come in as 0, so dump the whole buffer. Limit the size X of what we dump however if we've been keeping history of the buffer X using `094i`094j mode. In that case the echlen number is the number of X chars we dump. */ X`009 if (echnew`091n`093 != 1)`123 X`009 to_term(buffer`091n`093, buflen`091n`093, n); X`009 `125 X`009 if (echnew`091n`093 == 1)`123 X/* send only last 'echlen' bytes to terminal if not in full-buffer mode */ X/* If buflen`091n`093 < echlen`091n`093, normal send. */ X`009 if (buflen`091n`093 <= echlen`091n`093)`123 X`009 to_term(buffer`091n`093, buflen`091n`093, n); X`009 `125 X`009 if (buflen`091n`093 > echlen`091n`093)`123 X`009 to_term(buffer`091n`093+buflen`091n`093-echlen`091n`093, echlen` V091n`093, n); X`009 `125 X`009 echnew`091n`093 = 0; X`009 `125 X`009 if (bufmod2`091n`093 == 0) X`009`009buflen`091n`093 = 0; X`009 else X`009`009bufmod`091n`093 = 1; X`009`125 else /* emit the buffer we currently have to terminal */ X`009 to_term(tpptr, count`091n`093, n); X`009if (blocked`091n`093) X`009 to_term(tpptr, count`091n`093, n); X `125 else X`009to_term(tpptr, count`091n`093, n); X X /* Process boss_switch and boss_stuff logicals if present */ X X j = SYS$TRNLNM(0, &d_lnm_job, &d_boss_switch, &super_ac_mode, &trnlnm_it Vem); X if (!bad(j) && trnlnm_string_len == 1) `123 X`009j = LIB$DELETE_LOGICAL(&d_boss_switch, &d_lnm_job); X`009nname = toupper(trnlnm_string`0910`093); X`009j = SYS$TRNLNM(0, &d_lnm_job, &d_boss_stuff, &super_ac_mode, &trnlnm_ite Vm); X`009if (!bad(j)) `123 X`009 j = LIB$DELETE_LOGICAL(&d_boss_stuff, &d_lnm_job); X`009 trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`125 else `123 X`009 trnlnm_string`0910`093 = '\0'; X`009`125 X`009if (nname >= first_name && nname <= last_name) `123 X`009 mode`091n`093 = 'w'; X`009 mov_to(nname, 0, trnlnm_string, defproc); X`009`125 X `125 X if (py_post`091n`093 == 0) `123 X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LINESZ V-4)); X#endif X`009py_post`091n`093 = 1; X `125 X blocked`091n`093 = 0; X`125 X Xint Xcount_processes() X`123 X int j, i = 0; X X for (j = 0; j < nproc; j++) X`009if (name`091j`093 > 0) X`009 i++; X return (i); X`125 X Xdiag() X`123 X char bufa`0918`093; X int j; X X if (count_processes()) `123 X`009sprintf(buf, "%s`091Processes:", bos); X`009for (j = 0; j < nproc; j++) `123 X`009 if (name`091j`093 > 0) `123 X`009`009if (j == cur) X`009`009 sprintf(bufa, " %c%c*", name`091j`093, mode`091j`093); X`009`009else if (blocked`091j`093) X`009`009 sprintf(bufa, " %c%c+", name`091j`093, mode`091j`093); X`009`009else if (buflen`091j`093 > 0) X`009`009 sprintf(bufa, " %c%c-", name`091j`093, mode`091j`093); X`009`009else X`009`009 sprintf(bufa, " %c%c", name`091j`093, mode`091j`093); X`009`009strcat(buf, bufa); X`009 `125 X`009`125 X`009strcat(buf, "`093 "); X`009strcat(buf, ceoln); X `125 else X`009sprintf(buf, "%s`091No processes`093 %s", bos, ceoln); X term_msg(buf); X`125 X Xint Xnext_slot() X`123 X int j = 0; X while ((j < nproc) && name`091j`093) X`009j++; X return (j == nproc) ? -1 : j; X`125 X Xterm_msg(msg) X char *msg; X`123 X to_term(msg, strlen(msg), cur); X`125 X Xchar * Xget_image(pid)`009`009`009/* Get the image name for a process */ X int pid; X`123 X int j, item; X short len; X char *ptr, *ptra; X $DESCRIPTOR(d_image, image); X ptr = ℑ X if (pid == 0) X`009strcpy(image, ""); X else `123 X`009item = JPI$_IMAGNAME; X`009j = LIB$GETJPI(&item, &pid, 0, 0, &d_image, &len); X`009if (bad(j)) X`009 strcpy(image, ""); X`009else `123 X`009 image`091len`093 = '\0'; X`009 if (len == 0) `123 X`009`009item = JPI$_CLINAME; X`009`009j = LIB$GETJPI(&item, &pid, 0, 0, &d_image, &len); X`009`009if (bad(j)) X`009`009 strcpy(image, ""); X`009`009else X`009`009 image`091len`093 = '\0'; X`009 `125 else `123 X`009`009if ((ptr = strrchr(image, '`093'))) X`009`009 ptr++; X`009`009else X`009`009 ptr = ℑ X`009`009if (ptra = strchr(ptr, '.')) X`009`009 *ptra = '\0'; X`009 `125 X`009`125 X `125 X return (ptr); X`125 X Xint Xmov_to(nname, clear, string, proc_mode)`009/* Switch to process */ X char nname, *string;`009`009/* string is stuffed into input */ X int clear, proc_mode; /* proc_mode says whether to create V process */ X`123 X int ncur, len, i, j; X char *prefix; X prefix = clear ? clr : bos; X len = strlen(string); X if ((cur >= 0) && (name`091cur`093 == nname)) `123`009/* Redundant move V */ X`009bufmod`091cur`093 = 0; X`009mode`091cur`093 = pmode`091cur`093; X`009if (len == 0 & !uw) `123 X`009 sprintf(buf, "%s`091Already in process %c%c, %s`093%s", X`009`009 prefix, nname, mode`091cur`093, get_image(pid`091cur`093), ceoln V); X`009 term_msg(buf); X`009`125 X`009j = 1; X `125 else if ((ncur = procno`091nname - first_name`093) >= 0) `123`009/* V Existing proc */ X`009cur = ncur; X`009mode`091cur`093 = pmode`091cur`093; X`009echnew`091cur`093 = 0; X`009if(bufmod`091cur`093 != 0) echnew`091cur`093 = 1; X`009bufmod`091cur`093 = 0; X`009if (!uw) `123 X`009 sprintf(buf, "%s`091Switch to process %c%c, %s`093%s", X`009`009 prefix, name`091cur`093, mode`091cur`093, get_image(pid`091cur`093 V), ceoln); X`009 term_msg(buf); X`009`125 X`009if (blocked`091cur`093 `124`124 buflen`091cur`093 > 0) X`009 term_out(cur); X`009j = 1; X `125 else if (proc_mode == SWITCH) `123 X`009sprintf(buf, X`009 "%s`091Process %c nonexistent\007 (type %s C-%c %c to create it)`093%s V", X`009`009bos, nname, ctlchar_str, defproc == TOP ? 't' : 'n', X`009`009clear ? nname : tolower(nname), ceoln); X`009term_msg(buf); X`009len = 0; X`009j = 0; X `125 else if ((ncur = (uw ? (nname - first_name) : next_slot())) < 0) `1 V23 X`009if (cur >= 0) X`009 sprintf(buf, "%s`091No process slots left--still in %c%c`093%s", X`009`009 bos, name`091cur`093, mode`091cur`093, ceoln); X`009else X`009 sprintf(buf, "%s`091No process slots left`093%s", bos, ceoln); X`009term_msg(buf); X`009len = 0; X`009j = 0; X `125 else `123 X`009if (!uw) `123 X`009 if (proc_mode == CREATE) X`009`009sprintf(buf, "%s`091Starting subprocess %c...%s", prefix, nname, ceo Vl); X`009 else if (proc_mode == TOP) X`009`009sprintf(buf, "%s`091Starting top-level process %c...%s", prefix, nna Vme, ceol); X`009 term_msg(buf); X`009`125 X`009j = fire_up(ncur, nname, proc_mode); X`009if (bad(j)) `123 X`009 if (!uw) `123 X`009`009if (cur >= 0) X`009`009 sprintf(buf, "failed!!\007--still in %c%c`093%s", X`009`009`009 name`091cur`093, mode`091cur`093, ceoln); X`009`009else X`009`009 sprintf(buf, "failed!!\007`093%s", ceoln); X`009 `125 else `123 X`009`009sprintf(buf, "%s`091Couldn't start start process %c`093%s", X`009`009`009prefix, nname, ceoln); X`009`009uw_fun(P1_FN_KILLW `124 ((ncur + 1) & P1_WINDOW), 0, 0); X`009 `125 X`009 term_msg(buf); X`009 len = 0; X`009`125 else `123 X`009 if (!uw) `123 X`009`009sprintf(buf, "done; now in process %c%c, %s`093%s\r", X`009`009`009nname, mode`091ncur`093, get_image(pid`091ncur`093), ceol); X`009`009term_msg(buf); X`009 `125 X`009 cur = ncur; X`009 if (blocked`091cur`093) X`009`009term_out(cur); X`009`125 X `125 X /* if (j && uw && !mac_command) uw_fun(P1_FN_ISELW `124 ((cur + 1) & X * P1_WINDOW), 0, 0); */ X#ifndef USE_PTD X for (i = 0; i < len; i++) `123 X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 string + i, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X if ( len ) `123 X strncpy(otpline`091ncur`093,string,len); X check(PTD$WRITE(py_chn`091ncur`093, 0, 0, otpline`091ncur`093-4, len, V 0, 0)); X `125 X#endif X/* Handle emitchr string */ X if ((emitchr`091cur`093`0910`093 != '\0') && (emitlen`091cur`093 > 0))`1 V23 X#ifndef USE_PTD X for (i = 0; i < emitlen`091cur`093; i++) `123 X`009 check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 &emitchr`091cur`093`091i`093, 1, 0, 0, 0, 0)); X`009 if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X if ( emitlen`091ncur`093 ) `123 X strncpy(otpline`091ncur`093,emitchr`091ncur`093,emitlen`091ncur`093); X check(PTD$WRITE(py_chn`091ncur`093, 0, 0, otpline`091ncur`093-4, emit Vlen`091ncur`093, 0, 0)); X `125 X#endif X `125 X/* */ X return (j); X`125 X Xprint_help() X`123 X if (ctlchar >= 0 && ctlchar < 040) X`009sprintf(buf, "%sBOSS commands are preceded by %s (control-%c). \ XThe commands are:%s", bos, ctlchar_str, tolower(ctlchar + 0100), ceoln); X else X`009sprintf(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 immediately%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-x Quit when no more processes active%s", ceoln V); 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) `123 X`009sprintf(buf, "\r %c Clear screen and switch to process %c%s", X`009`009first_name, first_name, ceoln); X`009term_msg(buf); X `125 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 subprocess%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-i Toggle buffering of active output%s", ceoln) V; X term_msg(buf); X sprintf(buf, "\r C-j Toggle multishot buffering%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-l Toggle logging to BOSSn.LOG%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-e Close logfile BOSSn.LOG%s", ceoln); X term_msg(buf); X sprintf(buf, "\r + Enter cmd mode for 1 cmd%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-g Get n lines of cur proc -> next%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 V", 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`125 X Xvoid Xstart_logging(cur) X int cur; X`123 X char lognam`09180`093; X X logmod`091cur`093 = 1; X if (logfd`091cur`093 == 0) `123 X`009/* no open logfile yet, compose name and open */ X`009strcpy(lognam, log_file_prefix); X`009lognam`091log_file_prefix_len`093 = name`091cur`093; X`009strcpy(&lognam`091log_file_prefix_len + 1`093, ".LOG"); X`009logfd`091cur`093 = creat(lognam, 0, "mbf=3"); X `125 X`125 X X/* X Read on real terminal server X This routine will either be called at AST level for physical terminal X reads (on_AST_level true), or from main level in case of playback (false) V. X*/ X Xtt_srv(on_AST_level) X int on_AST_level; X`123 X int i; X int k, kk, kkk, kkkk; X int n; X char nname, nmode, *desc, dismiss, function, arg; X char lognam`09180`093; X char *lnptr; X X if (quit_in_progress) X`009return;`009`009`009/* ignore AST from sys$cancel */ X X check(tiosb.stats); X X dismiss = 0; X X if (playback && on_AST_level) `123 X`009/* User interrupts a playback session */ X`009if (keyboard_locked) `123 X`009 /* ignoring keyboard */ X`009 dismiss = 1; X`009`125 else `123 X`009 playback = 0; X`009 /* todo: main() may be in a delay sleep - wake up? */ X`009`125 X `125 X /* recording first */ X if (recording && !dismiss) `123 X`009double delay = elapsedtime(); X`009startclock(); X`009if (delay > DELAY_THR) `123 X`009 /* write a delay entry if more than DELAY_THR secs between X`009 * keystrokes */ X`009 delay *= 10.0;`009/* convert to 100 millisecs units */ X`009 sprintf(buf, "%c%d\n", DELAY_ESC, (int) delay); X`009 write(record_fd, buf, strlen(buf)); X`009`125 X`009if (input_char == DELAY_ESC) X`009 write(record_fd, &input_char, 1); X`009write(record_fd, &input_char, 1); X `125 X /* do UW decoding at first */ X if (uw) `123 X`009mac_command = 1; X`009switch (uw_state) `123 X`009 case UW_NORMAL: X`009`009if (input_char == P1_IAC) `123 X`009`009 uw_state = UW_PENDING; X`009`009 dismiss = 1; X`009`009`125 X`009`009break; X`009 case UW_PENDING: X`009`009uw_state = UW_NORMAL; X`009`009dismiss = 1; X`009`009if ((input_char & P1_DIR) == P1_DIR_MTOH) `123 X`009`009 function = input_char & P1_FN; X`009`009 arg = input_char & P1_WINDOW; X`009`009 switch (function) `123 X`009`009`009case P1_FN_NEWW: X`009`009`009 mov_to(first_name + (arg - 1), 0, "", defproc); X`009`009`009 break; X`009`009`009case P1_FN_KILLW: X`009`009`009 if (name`091arg - 1`093 > 0 && proc_type`091arg - 1`093 != T VOP) X`009`009`009`009st = SYS$DELPRC(&pid`091arg - 1`093, 0); X`009`009`009 break; X`009`009`009case P1_FN_ISELW: X`009`009`009 mov_to(first_name + (arg - 1), 0, "", defproc); X`009`009`009 break; X`009`009`009case P1_FN_OSELW:`009/* shouldn't ever occur */ X`009`009`009 break; X`009`009`009case P1_FN_META: X`009`009`009 uw_meta = 1; X`009`009`009 break; X`009`009`009case P1_FN_CTLCH: X`009`009`009 dismiss = 0; X`009`009`009 switch (arg) `123 X`009`009`009`009case P1_CC_IAC: X`009`009`009`009 input_char = P1_IAC; X`009`009`009`009 break; X`009`009`009`009case P1_CC_XON: X`009`009`009`009 input_char = XON; X`009`009`009`009 break; X`009`009`009`009case P1_CC_XOFF: X`009`009`009`009 input_char = XOFF; +-+-+-+-+-+-+-+- END OF PART 4 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 5 -+-+-+-+-+-+-+-+ X`009`009`009`009 break; X`009`009`009`009default: X`009`009`009`009 dismiss = 1; X`009`009`009`009 break; X`009`009`009 `125 X`009`009`009 break; X`009`009`009case P1_FN_MAINT: X`009`009`009 switch (arg) `123 X`009`009`009`009case P1_MF_ENTRY: /* Shouldn't get this */ X`009`009`009`009 break; X`009`009`009`009case P1_MF_ASKPCL: X`009`009`009`009 uw_fun(P1_FN_MAINT `124 P1_MF_CANPCL, 040, 1); X`009`009`009`009 break; X`009`009`009`009case P1_MF_CANPCL: /* Shouldn't get this */ X`009`009`009`009 uw_state = UW_CANPCL; X`009`009`009`009 break; X`009`009`009`009case P1_MF_SETPCL: X`009`009`009`009 uw_state = UW_SETPCL; X`009`009`009`009 break; X`009`009`009`009case P1_MF_EXIT: X`009`009`009`009 exit(SS$_NORMAL); X`009`009`009`009 break; X`009`009`009 `125 X`009`009`009 break; X`009`009`009case UW_CANPCL: X`009`009`009 if (input_char == 040) X`009`009`009`009uw_fun(P1_MF_SETPCL, 040, 1); X`009`009`009 else X`009`009`009`009uw_fun(P1_MF_CANPCL, 040, 1); X`009`009`009 uw_state = UW_NORMAL; X`009`009`009 break; X`009`009`009case UW_SETPCL: X`009`009`009 if (input_char != 040) `123 X`009`009`009`009sprintf(buf, X`009`009`009`009`009"%s`091Don't understand this protocol: %d`093%s", X`009`009`009`009`009bos, input_char, ceoln); X`009`009`009 `125 X`009`009`009 uw_state = UW_NORMAL; X`009`009`009 break; X`009`009 `125 X`009`009`125 X`009`125 X`009if (uw_meta && !dismiss) `123 X`009 uw_meta = 0; X`009 input_char = 0200 `124 input_char; X`009`125 X`009mac_command = 0; X `125 X if (!dismiss) `123 X`009if (input_char == 0177) X`009 input_char = delete_char; X`009else if (input_char == delete_char) X`009 input_char = 0177; X`009if (input_state == NORMAL && cur < 0) X`009 input_state = PENDING; X`009switch (input_state) `123 X`009 case NORMAL: X`009`009if (input_char == ctlchar) X`009`009 input_state = PENDING; X`009`009else `123 X`009`009 to_pty(on_AST_level, input_char); X`009`009`125 X`009`009break; X`009 case PENDING: X`009`009if (input_char == ctlchar) `123 X`009`009 if (cur >= 0) `123 X`009`009`009to_pty(on_AST_level, input_char); X`009`009`009input_state = NORMAL; X`009`009 `125 X`009`009 break; X`009`009`125 X`009`009switch (input_char) `123 X`009`009 case '+':`009/* Plus sign */ X/* Fire up command mode */ X/* Command mode is responsible for its' own prompting, etc. */ X`009`009`009cmdmode(cur); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\016':`009/* C-n */ X`009`009`009input_state = CREATE; X`009`009`009break; X`009`009 case '\024':`009/* C-t */ X`009`009`009input_state = TOP; X`009`009`009break; X`009`009 case '\030':`009/* C-x */ X`009`009`009synchr_quit = TRUE; X`009`009`009sprintf(buf, X`009`009`009`009"%s`091Boss: will exit when processes terminate`093%s", X`009`009`009`009bos, ceoln); X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\032':`009/* C-z */ X`009`009`009if (count_processes()) `123 X`009`009`009 diag(); X`009`009`009 sprintf(buf, X`009`009`009 `009 "`091Do you really want to quit (y or n)?`093%s\007" V, X`009`009`009`009 ceol); X`009`009`009 term_msg(buf); X`009`009`009 input_state = END; X`009`009`009`125 else X`009`009`009 exit(SS$_NORMAL); X`009`009`009break; X`009`009 case '\007':`009/* C-g */ X`009`009`009if (cur < 0) `123 X`009`009`009 term_msg("\007"); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009 "%s`091Enter # lines to move (1-9):%s", bos, ceoln); X`009`009`009 term_msg(buf); X`009`009`009 kprc = cur; X`009`009`009 input_state = CUTP; X`009`009`009`125 X`009`009`009break; X`009`009 case '\013':`009/* C-k */ X`009`009`009if (cur < 0) `123 X`009`009`009 term_msg("\007"); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else if (proc_type`091cur`093 == TOP) `123 X`009`009`009 sprintf(buf, "%s`091Can't kill top-level process %c`093%s\00 V7", X`009`009`009`009 bos, name`091cur`093, ceoln); X`009`009`009 term_msg(buf); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009`009 "%s`091Do you really want to kill process %c (y or n)?`0 V93%s\007", X`009`009`009`009 bos, name`091cur`093, ceol); X`009`009`009 term_msg(buf); X`009`009`009 kill_proc = cur; X`009`009`009 input_state = KILL; X`009`009`009`125 X`009`009`009break; X`009`009 case '\010':`009/* C-h */ X`009`009`009print_help(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '?': X`009`009`009diag(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\002':`009/* C-b */ X`009`009 case '\017':`009/* C-o */ X`009`009 case '\020':`009/* C-p */ X`009`009 case '\027':`009/* C-w */ X`009`009`009if (input_char == '\002') X`009`009`009 desc = "Buffer"; X`009`009`009else if (input_char == '\017') X`009`009`009 desc = "Discard"; X`009`009`009else if (input_char == '\020') X`009`009`009 desc = "Print"; X`009`009`009else if (input_char == '\027') X`009`009`009 desc = "Stop"; X`009`009`009nmode = input_char + 0140; X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output by default`093%s", X`009`009`009`009 bos, desc, ceoln); X`009`009`009`125 else `123 X`009`009`009 mode`091cur`093 = nmode; X`009`009`009 pmode`091cur`093 = nmode; X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output from process %c`093%s", X`009`009`009`009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\011':`009/* C-i */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = bufmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Actv Buffered"; X`009`009`009`009bufmod`091cur`093 = 1; X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Actv Unbuffered"; X`009`009`009`009bufmod`091cur`093 = 0; X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output from process %c`093%s", X`009`009`009`009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\012':`009/* C-j */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = bufmod2`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Multshot Buffered"; X`009`009`009`009bufmod2`091cur`093 = 1; X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Multshot Unbuffered"; X`009`009`009`009bufmod2`091cur`093 = 0; X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\014':`009/* C-l */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = logmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Logging enabled"; X`009`009`009`009start_logging(cur); X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Logging disabled"; X`009`009`009`009logmod`091cur`093 = 0; X`009`009`009`009/* do not close logfile yet, might get enable X`009`009`009`009 * later */ X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\005':`009/* C-e */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = logmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Logging enabled"; X`009`009`009`009start_logging(cur); X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Logging disabled"; X`009`009`009`009logmod`091cur`093 = 0; X`009`009`009`009k = close( logfd`091cur`093 ); X`009`009`009`009/* do not close logfile yet, might get enable X`009`009`009`009 * later */ X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\177':`009/* C-? */ X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 default: X`009`009`009nname = toupper(input_char); X`009`009`009if (nname >= first_name && nname <= last_name) `123 X`009`009`009 /* fill in any "cut/paste" text being brought in X`009`009`009 * from other proc */ X`009`009`009 n = cur; X`009`009`009 /* Zero text string if not being used */ X`009`009`009 trnlnm_string`0910`093 = '\0'; X`009`009`009 if (n >= 0 && cutpas`091n`093 > 0) `123 X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009/* Paste last n lines (up to max in buffer) X`009`009`009`009 * back */ X`009`009`009`009/* We are assured the dest. process number is X`009`009`009`009 * legal here */ X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* Count CR's (newlines) in buffer, then go X`009`009`009`009 * back by n of them and copy from there to X`009`009`009`009 * the end of buffer into the string that X`009`009`009`009 * would be used for boss_stuff work. X`009`009`009`009 * This avoids another mechanism. */ X`009`009`009`009kkk = k - cutpas`091n`093; X`009`009`009`009if (kkk < 0) X`009`009`009`009 kkk = 0; X`009`009`009`009/* reset save amount for next time */ X`009`009`009`009cutpas`091n`093 = 0; X`009`009`009`009kk = buflen`091n`093 + 100; X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009`009if (k == kkk) X`009`009`009`009`009 kk = kkkk; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* kk is now index into start of cut/paste X`009`009`009`009 * area, buflen`091n`093 = end */ X`009`009`009`009/* guard against empty buffer */ X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009if (kk < buflen`091n`093) `123 X`009`009`009`009 for (kkkk = kk; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009`009trnlnm_string`091trnlnm_string_len++`093 = X`009`009`009`009`009 buffer`091n`093`091kkkk`093; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`009`009 `125 X`009`009`009 /* end cut/paste */ X X`009`009`009 mov_to(nname, uw ? 0 : input_char < 'a', X`009`009`009`009 trnlnm_string, X`009`009`009`009 switch_create ? defproc : SWITCH); X`009`009`009`125 else X`009`009`009 term_msg("\007"); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009`125 X`009`009break; X`009 case CREATE: X`009 case TOP: X`009`009switch (input_char) `123 X`009`009 case '\016':`009/* C-n */ X`009`009`009input_state = CREATE; X`009`009`009break; X`009`009 case '\024':`009/* C-t */ X`009`009`009input_state = TOP; X`009`009`009break; X`009`009 case '\010':`009/* C-h */ X`009`009`009print_help(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '?': X`009`009`009diag(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\177':`009/* C-? */ X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 default: X`009`009`009nname = toupper(input_char); X`009`009`009if (nname >= first_name && nname <= last_name) `123 X`009`009`009 /* fill in any "cut/paste" text being brought in X`009`009`009 * from other proc */ X`009`009`009 n = cur; X`009`009`009 /* Zero text string if not being used */ X`009`009`009 trnlnm_string`0910`093 = '\0'; X`009`009`009 if (n >= 0 && cutpas`091n`093 > 0) `123 X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009/* Paste last n lines (up to max in buffer) X`009`009`009`009 * back. We are assured the dest. process X`009`009`009`009 * number is legal here */ X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* Count LF's (newlines) in buffer, then go X`009`009`009`009 * back by n of them and copy from there to X`009`009`009`009 * the end of buffer into the string that X`009`009`009`009 * would be used for boss_stuff work. X`009`009`009`009 * This avoids another mechanism. */ X`009`009`009`009kkk = k - cutpas`091n`093; X`009`009`009`009if (kkk < 0) X`009`009`009`009 kkk = 0; X`009`009`009`009/* reset save amount for next time */ X`009`009`009`009cutpas`091n`093 = 0; X`009`009`009`009k = 0; X`009`009`009`009kk = buflen`091n`093 + 100; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009`009if (k == kkk) X`009`009`009`009`009 kk = kkkk; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* kk is now index into start of cut/paste X`009`009`009`009 * area, buflen`091n`093 = end */ X`009`009`009`009/* guard against empty buffer */ X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009if (kk < buflen`091n`093) `123 X`009`009`009`009 for (kkkk = kk; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009`009trnlnm_string`091trnlnm_string_len++`093 = X`009`009`009`009`009 buffer`091n`093`091kkkk`093; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`009`009 `125 X`009`009`009 /* end cut/paste */ X`009`009`009 mov_to(nname, uw ? 0 : input_char < 'a', X`009`009`009`009 trnlnm_string, input_state); X`009`009`009`125 else X`009`009`009 term_msg("\007"); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009`125 X`009`009break; X`009 case END: X`009`009if (toupper(input_char) == 'Y') `123 X`009`009 term_msg(" Yes\r"); X`009`009 exit(SS$_NORMAL); X`009`009`125 else `123 X`009`009 term_msg(" No\r\n"); X`009`009`125 X`009`009input_state = NORMAL; X`009`009break; X`009 case CUTP: X`009`009/* kprc has proc. number to cut from */ X`009`009kkk = input_char; X`009`009/* Make sure char is 1 to 9, else discard and ignore */ X`009`009/* Add small bit to allow multiple digits of count */ X`009`009if (kkk > 48 && kkk < 58) `123 X`009`009 kk = cutpas`091kprc`093 * 10; X`009`009 cutpas`091kprc`093 = kk + kkk - 48; X`009`009 input_state = CUTP; X`009`009`125 else `123 X`009`009 input_state = NORMAL; X`009`009`125 X`009`009break; X`009 case KILL: X`009`009if (toupper(input_char) == 'Y') `123 X`009`009 if (kill_proc >= 0 && name`091kill_proc`093 > 0) `123 X`009`009`009if (proc_type`091kill_proc`093 == TOP) `123 X`009`009`009 sprintf(buf, X`009`009`009 `009"%s`091Can't kill top-level process %c`093%s\007", X`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009`125 else `123 X`009`009`009 st = SYS$DELPRC(&pid`091kill_proc`093, 0); X`009`009`009 if (bad(st)) X`009`009`009`009sprintf(buf, "%s`091Couldn't kill process %c`093%s", X`009`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009 else X`009`009`009`009sprintf(buf, "%s`091Killed process %c`093%s", X`009`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009`125 X`009`009 `125 else X`009`009`009sprintf(buf, "%s`091Process already killed`093%s", X`009`009`009`009bos, ceoln); X`009`009 term_msg(buf); X`009`009`125 else `123 X`009`009 term_msg(" No\r\n"); X`009`009`125 X`009`009input_state = NORMAL; X`009`009kill_proc = -1; X`009`009break; X`009`125 X `125 X /* re-post read AST on real term */ X /* but only if really on_AST_level */ X if (on_AST_level) `123 X`009check(SYS$QIO(0, tt_chn, IO$_READVBLK, &tiosb, &tt_srv, TRUE, X`009`009 &input_char, 1, 0, 0, 0, 0)); X `125 X`125 X Xuw_fun(code, arg, count) X char code, arg; X int count; X`123 X term_buf`0910`093 = P1_IAC; X term_buf`0911`093 = P1_DIR_HTOM `124 code; X if (count > 0) X`009term_buf`0912`093 = arg; X check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, 0, 0, X `009`009 term_buf, 2 + count, 0, 0, 0, 0)); X`125 X X/* cmdmode(cur); */ X/* Handle commands too intricate for normal work. Can use global cmdlin X to read data into. */ Xcmdmode(curprc) X int curprc; X`123 X int j,k,n; X term_msg("\r\nCmd>"); X/* zero the command line initially */ X for (j=0; j < 128; j++)`123 X cmdlin`091j`093 = '\0';`125 X check(SYS$QIOW(4,tt_chn,IO$_READVBLK, &tiosb,0,0,&cmdlin,126,0,0,0,0)); X term_msg(cmdlin); /* echo the line */ X/* got command line in now...go process it and return */ X/* Sstart-chars - set start chars in current process; ctrl-W a good choice * V/ X if (toupper(cmdlin`0910`093) == 'S')`123 X/* start charstring is rest of line */ X if(curprc >= 0)`123 X emitlen`091curprc`093 = 0; X for (j = 0; j <= 7 ; j++)`123 emitchr`091curprc`093`091j`093 = '\0';`1 V25 X for (j = 1; j < 7; j++)`123 X if (cmdlin`091j`093 == '\0')break; X if (cmdlin`091j`093 == '\r')break; X emitchr`091curprc`093`091j-1`093 = cmdlin`091j`093; X emitlen`091curprc`093++; X `125 X `125 X `125 X/* Gstart-chars - set start chars for all processes */ X if (toupper(cmdlin`0910`093) == 'G')`123 X/* start charstring is rest of line */ X for (k=0;k < NPROCMAX; k++)`123 X for (j = 0; j <= 7 ; j++)`123 emitchr`091k`093`091j`093 = '\0';`125 X emitlen`091k`093 = 0; X for (j = 1; j < 7; j++)`123 X if (cmdlin`091j`093 == '\0')break; X if (cmdlin`091j`093 == '\r')break; X emitchr`091k`093`091j-1`093 = cmdlin`091j`093; X emitlen`091k`093++; X `125 X `125 X `125 X/* Pnumber plays back only "number" chars for the buffer, not X the entire buffer size. "Number" must be between 100 and X BUFSIZE, the 100 chosen to allow current output by. */ X if(toupper(cmdlin`0910`093) == 'P')`123 X sscanf(&cmdlin`0911`093,"%d",&n); X`009printf("`091Setting save print to (%d)\n", X`009 n); X if(curprc >= 0)`123 X if ((n >= 100) && ( n <= BUFSIZE))`123 X k = n; X `125else`123 X k = BUFSIZE;`125 X echlen`091curprc`093 = k; X `125 X `125 X/* Anumber plays back only "number" chars for the buffer, not X the entire buffer size. "Number" must be between 100 and X BUFSIZE, the 100 chosen to allow current output by. */ X/* Unlike Pnumber, Anumber operates on all processes. */ X if(toupper(cmdlin`0910`093) == 'A')`123 X sscanf(&cmdlin`0911`093,"%d",&n); X`009printf("`091Setting save prints to (%d)\n", X`009 n); X for (j=0; j < NPROCMAX ; j++)`123 X if ((n >= 100) && ( n <= BUFSIZE))`123 X k = n; X `125else`123 X k = BUFSIZE;`125 X echlen`091j`093 = k; X `125 X `125 X`125 X Xget_tt_info() X`123 X $DESCRIPTOR(d_tt, "SYS$COMMAND"); X /* Get a channel & mailbox of terminal */ X check(LIB$ASN_WTH_MBX(&d_tt, &TTMBSIZ, &TTMAXSIZ, &tt_chn, &tt_mb_chn)); X /* Get the terminal characteristics. */ X check(SYS$QIOW(0, tt_chn, IO$_SENSEMODE, 0, 0, 0, X `009`009 &tt_chr, TTCHRLEN, 0, 0, 0, 0)); X tt_sav_chr = tt_chr; X tt_chr.ttchr `124= TT$M_NOECHO;/* term will be Noecho */ X tt_chr.ttchr &= `126TT$M_ESCAPE;`009/* no escape */ X tt_chr.ttchr &= `126TT$M_HOSTSYNC;`009/* no host sync */ X if (flow_control) X`009tt_chr.ttchr `124= TT$M_TTSYNC;`009/* do sync at BOSS level */ X else X`009tt_chr.ttchr &= `126TT$M_TTSYNC;`009/* do sync at subprocess level */ X tt_chr.xchar `124= TT2$M_PASTHRU;`009/* it will be PASTRHU */ X if (brkthru) `123 X`009tt_chr.ttchr `124= TT$M_MBXDSABL;`009/* no hangup messages */ X`009tt_chr.ttchr `124= TT$M_NOBRDCST;`009/* disable direct broadcast */ X`009tt_chr.xchar `124= TT2$M_BRDCSTMBX;`009/* send them to mailbox X`009`009`009`009`009`009 * instead */ X `125 X check(SYS$QIOW(0, tt_chn, IO$_SETMODE, 0, 0, 0, X `009`009 &tt_chr, TTCHRLEN, 0, 0, 0, 0)); X`125 X Xfix_a_tp(n)`009`009`009/* Set up a Pseudo term */ X int n; X`123 X int dev_depend, tp_chn, blk, status; X struct CHARBLK tw_chr; X struct IOSBBLK iosb; X#ifndef USE_PTD X struct DVIBLK dvi_stuff = `1234, DVI$_DEVDEPEND, &dev_depend, 0, 0`125; X#else X struct DVIBLK dvi_stuff = `1234, DVI$_UNIT, &dev_depend, 0, 0`125; X long inadr`0912`093;`009`009/* for LIB$GET_VM_PAGE */ X#endif X X#ifndef USE_PTD X $DESCRIPTOR(d_pynam, "PYA0:");`009/* Template. */ X $DESCRIPTOR(d_finaltp, &finaltp`091n`093); X /* Assign a mailbox to PYA */ X check(LIB$ASN_WTH_MBX(&d_pynam, &MBSIZ, &MAXSIZ, &py_chn`091n`093, X `009`009`009 &py_mb_chn`091n`093)); X /* Use $GETDVI to get the device dependent characteristics, which X * contains the associated terminal device's unit number. */ X check(SYS$GETDVI(0, py_chn`091n`093, 0, &dvi_stuff, &iosb, 0, 0, 0)); X check(iosb.stats); X#endif X X tw_chr = tt_sav_chr; X tw_chr.xchar `124= TT2$M_HANGUP; X X#ifndef USE_PTD X sprintf(finaltp`091n`093, "TWA%d:", dev_depend); X d_finaltp.dsc$w_length = strlen(&finaltp`091n`093); X /* Get a channel on this TWA */ X if (bad(SYS$ASSIGN(&d_finaltp, &tp_chn, 0, 0))) `123 X`009sprintf(&finaltp`091n`093, "TPA%d:", dev_depend);`009/* TWA doesn't work V; X`009`009`009`009`009`009`009 * try TPA */ X`009d_finaltp.dsc$w_length = strlen(&finaltp`091n`093); X`009check(SYS$ASSIGN(&d_finaltp, &tp_chn, 0, 0)); X `125 X if (no_phy_io) X`009check(SYS$SETPRV(1, &priv, 0, 0)); X /* Make it look like a terminal */ X if (bad(SYS$QIOW(0, tp_chn, IO$_SETCHAR, 0, 0, 0,`009/* This needs PHY_I VO X`009`009`009`009`009`009`009 * priv */ X`009`009 &tw_chr, TTCHRLEN, 0, 0, 0, 0))) X`009check(SYS$QIOW(0, tp_chn, IO$_SETMODE, 0, 0, 0, X`009`009 &tw_chr, TTCHRLEN, 0, 0, 0, 0)); X if (no_phy_io) X`009check(SYS$SETPRV(0, &priv, 0, 0)); X check(SYS$DASSGN(tp_chn));`009/* We don't need it. only the mailbox */ X /* in fact keeping it kills us. */ X#else X blk = 4 * 512;`009`009/* 2 plus 2 guard pages */ X status = LIB$GET_VM_PAGE(&blk,&inadr`0910`093); X if (status == LIB$_INSVIRMEM) `123`009/* If we can't get the memory, just V */ X sprintf(buf,"No memory left!!..."); /* say so rather than crashing out * V/ X term_msg(buf);`009`009`009/* killing all the processes. */ X return (status); X `125 X check(status); X tpline`091n`093 = (char *)((inadr`0910`093 += 512) +4);`009/* where data g Voes */ X inadr`0911`093 = inadr`0910`093 + 6 * 512; X otpline`091n`093 = tpline`091n`093 + 3 * 512;`009`009/* split the differen Vce? */ X X/* comp_srv will get notify if ptd exits via spawn */ X if (proc_type`091n`093 == TOP) `123 X check(PTD$CREATE(&tp_chn,0,&tw_chr,TTCHRLEN,&comp_srv,n,0,&inadr`0910` V093)); X `125 else `123 X check(PTD$CREATE(&tp_chn,0,&tw_chr,TTCHRLEN,0,0,0,&inadr`0910`093)); X `125 X py_chn`091n`093 = tp_chn; X/* X * Use $GETDVI to get the device dependent characteristics, which X * contains the associated terminal device's unit number. X */ X check(SYS$GETDVI(0,py_chn`091n`093,0,&dvi_stuff,&iosb,0,0,0)); X check(iosb.stats); X sprintf(finaltp`091n`093,"FTA%d:",dev_depend); X#endif X return (1); X`125 X Xbroadcast_handler() X`123`009`009`009`009/* handle broadcasts to BOSS */ X int j, len; X X $DESCRIPTOR(d_tt_mb, tt_mb); X $DESCRIPTOR(d_finaltp, finaltp`091cur`093); X X check(tiosbmb.stats);`009/* Check status */ X len = ((0377 & tt_mb`09121`093) << 8) + (0377 & tt_mb`09120`093); /* mes Vsage length */ X if (cur < 0) `123 X`009term_msg("\r\n"); X`009to_term(&(tt_mb`09122`093), len, 1); X`009term_msg("\r"); X `125 else `123 X`009d_tt_mb.dsc$w_length = len; X`009d_tt_mb.dsc$a_pointer = &(tt_mb`09122`093); X`009if (no_oper) X`009 check(SYS$SETPRV(1, &privs, 0, 0)); X`009check(SYS$BRKTHRU(0, &d_tt_mb, &d_finaltp, X`009`009`009 BRK$C_DEVICE, 0, 32, 0, BRK$C_USER16, 0, 0, 0)); X`009if (no_oper) X`009 check(SYS$SETPRV(0, &privs, 0, 0)); X `125 X check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, &broadcast_handler, V 0, X`009`009 &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X`125 X Xpost_term_reads()`009`009/* Read AST on real term */ X`123 X if (brkthru) `123 X`009check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, X`009`009 &broadcast_handler, 0, &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X `125 else `123 X`009check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, 0, 0, X`009`009 &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X `125 X check(SYS$QIO(0, tt_chn, IO$_READVBLK, &tiosb, &tt_srv, TRUE, X`009`009 &input_char, 1, 0, 0, 0, 0)); X`125 X Xpost_pty_reads(n)`009`009/* Post read AST on Pseudo-term */ X int n; X`123 X char cr = '\r'; +-+-+-+-+-+-+-+- END OF PART 5 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 6 -+-+-+-+-+-+-+-+ X X if (init) X`009return (0); X#ifndef USE_PTD X py_post`091n`093 = 1; X check(SYS$QIO(0, py_mb_chn`091n`093, IO$_READVBLK, &miosb`091n`093, &mb_ Vsrv, n, X`009`009 &py_mb`091n`093, MBSIZ, 0, 0, 0, 0)); X check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 &tpline`091n`093, LINESZ, 0, 0, 0, 0)); X#else X check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LINESZ V-4)); X#endif X if (proc_type`091n`093 == TOP) `123 X#ifndef USE_PTD X`009check(SYS$QIOW(0, py_chn`091n`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 &cr, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X#else X otpline`091n`093`0910`093 = cr; X check(PTD$WRITE(py_chn`091n`093,0,0,otpline`091n`093-4,1,0,0)); X/* should wait for completion? */ X#endif X `125 X`125 X Xint Xfire_up(n, nname, proc_mode)`009/* Fire up subprocess n */ X int n, proc_mode; X char nname; X`123 X int val, status; X name`091n`093 = nname; X procno`091nname - first_name`093 = n; X count`091n`093 = 0;`009`009/* Initialize buffer count */ X blocked`091n`093 = 0;`009`009/* It starts unblocked */ X bufmod`091n`093 = 0;`009`009/* Starts w/o buffering all */ X bufmod2`091n`093 = 0; X logmod`091n`093 = 0;`009`009/* no logging initially */ X logfd`091n`093 = 0;`009`009/* no fd either */ X py_post`091n`093 = 0; X mode`091n`093 = defmode; X pmode`091n`093 = defmode; X buflen`091n`093 = 0; X proc_type`091n`093 = proc_mode; X enable_hangup`091n`093 = 0; X pid`091n`093 = 0; X status = fix_a_tp(n);`009/* Set a pseudo terminal by TT info */ X#ifndef USE_PTD X check(SYS$CANCEL(py_chn`091n`093)); /* Don't need this Half of pseudo- Vter */ X#endif X val = (proc_type`091n`093 == TOP) ? status : X`009low_lib_spawn(n, finaltp`091n`093, &pid`091n`093, name`091n`093); /* Spa Vwn a subprocess */ X if (!bad(val)) `123 X`009if (auto_log) start_logging(n);`009/* if requested by /LOG */ X`009post_pty_reads(n);`009/* Set up AST */ X`009if (uw && !mac_command) X`009 uw_fun(P1_FN_NEWW `124 ((n + 1) & P1_WINDOW), 0, 0); X `125 else X`009comp_srv(n);`009`009/* Mark the process as non-existent */ X return (val); X`125 X Xinitialize() X`123`009`009`009`009/* Initialize everything */ X int j, item; X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_lnm_process, "LNM$PROCESS"); X X nalph = last_name - first_name + 1; X for (j = 0; j < nproc; j++) X`009name`091j`093 = '\0';`009`009/* Initialize variables */ X for (j = 0; j < nalph; j++) X`009procno`091j`093 = -1; X for (j = 0; j < nalph; j++)`123 X`009emitchr`091j`093`0910`093 = '\0'; X`009emitlen`091j`093 = 0; X`009echlen`091j`093 = BUFSIZE; X echnew`091j`093 = 0; X `125 X /* Save old value of BOSS$ID */ X j = SYS$TRNLNM(0, &d_lnm_process, &d_boss_id, X `009`009 &super_ac_mode, &trnlnm_item); X if (!bad(j) && trnlnm_string_len == 1) `123 X`009oboss_id = trnlnm_string`0910`093; X`009j = LIB$DELETE_LOGICAL(&d_boss_id, 0); X `125 X item = JPI$_PROCPRIV;`009/* Check whether have PHY_IO & OPER */ X check(LIB$GETJPI(&item, 0, 0, &priv, 0, 0)); X no_phy_io = !(priv`0910`093 & PRV$M_PHY_IO); X no_oper = !(priv`0910`093 & PRV$M_OPER); X item = JPI$_IMAGPRIV;`009/* Check whether we can do BRKTHRU */ X check(LIB$GETJPI(&item, 0, 0, &priv, 0, 0)); X brkthru = ((priv`0910`093 & PRV$M_OPER) `124`124 !no_oper); X priv`0910`093 = PRV$M_PHY_IO; X priv`0911`093 = 0; X privs`0910`093 = PRV$M_OPER; X privs`0911`093 = 0; X if (no_phy_io) X`009check(SYS$SETPRV(0, &priv, 0, 0)); X if (no_oper) X`009check(SYS$SETPRV(0, &privs, 0, 0)); X get_tt_info();`009`009/* Initialize terminal */ X if (uw) X`009uw_fun(P1_FN_MAINT `124 P1_MF_ENTRY, 0, 0); X start_up();`009`009`009/* Start up processes */ X if (recording) `123 X`009record_fd = creat(record_file, 0, "mbf=3"); X`009if (record_fd < 0) `123 X`009 perror(record_file); X`009 exit(0); X`009`125 X`009startclock(); X `125 X if (playback) `123 X`009playback_fd = open(playback_file, O_RDONLY, 0, "mbf=3"); X`009if (playback_fd < 0) `123 X`009 perror(playback_file); X`009 exit(0); X`009`125 X `125 X post_term_reads(); X`125 X X/* Next two routines taken from FILE program by Joe Meadows Jr. */ X Xlong int Xcli_present(s) X char *s; X`123 X static struct dsc$descriptor s_desc = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_ VS, 0`125; X X s_desc.dsc$w_length = strlen(s); X s_desc.dsc$a_pointer = s; X return (cli$present(&s_desc)); X`125 X Xlong int Xcli_get_value(s1, s2) X char *s1, **s2; X`123 X static struct dsc$descriptor s1_desc = X `009`1230, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`125; X static struct dsc$descriptor s2_desc = X `009`1230, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`125; X static char null = '\0'; X static struct dsc$descriptor null_desc = X `009`1231, DSC$K_DTYPE_T, DSC$K_CLASS_S, &null`125; X long int status; X X s1_desc.dsc$w_length = strlen(s1); X s1_desc.dsc$a_pointer = s1; X X status = cli$get_value(&s1_desc, &s2_desc); X X if (status & 1) `123 X`009str$append(&s2_desc, &null_desc); X`009*s2 = s2_desc.dsc$a_pointer; X `125 else X`009*s2 = 0; X return (status); X`125 X Xprocess_command_line() X`123 X long int status, boss_len; X short int length; X $DESCRIPTOR(d_line, buf); X $DESCRIPTOR(d_cldline, buf); X $DESCRIPTOR(d_boss_term, "BOSS$TERM"); X $DESCRIPTOR(d_lnm_file_dev, "LNM$FILE_DEV"); X X strcpy(buf, "BOSS "); X boss_len = strlen(buf); X d_line.dsc$w_length = d_line.dsc$w_length - boss_len; X d_line.dsc$a_pointer = d_line.dsc$a_pointer + boss_len; X check(lib$get_foreign(&d_line, 0, &length, 0)); X buf`091length + boss_len`093 = '\0'; X d_cldline.dsc$w_length = length + boss_len; X status = cli$dcl_parse(&d_cldline, BOSS_CLD, 0, 0, 0); X if (bad(status)) X`009exit(STS$K_ERROR + STS$M_INHIB_MSG); X X status = cli_present("UW"); X uw = !bad(status); X X if (!uw) `123 X`009nproc = NPROCMAX; X`009defmode = 'b'; X`009first_name = 'A'; X`009last_name = 'Z'; X `125 else `123 X`009nproc = P1_NWINDOW; X`009defmode = 'p'; X`009first_name = '1'; X`009last_name = '7'; X `125 X X status = cli_get_value("COMMAND_CHARACTER", &retval); X if (bad(status)) `123 X`009if (!uw) X`009 ctlchar = 034;`009/* C-\ */ X`009else X`009 ctlchar = -1; X `125 else X`009sscanf(retval, "%d", &ctlchar); X if (ctlchar < (uw ? -1 : 0) `124`124 ctlchar > 0177 `124`124 ctlchar == V 032) `123 X`009printf("`091Illegal command character (%d); using C-\\ instead`093\n", X`009 ctlchar); X`009ctlchar = 034;`009`009/* C-\ */ X`009/* disallow C-z as a command character */ X `125 X if (ctlchar >= 0 && ctlchar < 040) X`009sprintf(ctlchar_str, "C-%c", tolower(ctlchar + 0100)); X else if (ctlchar == 040) X`009strcpy(ctlchar_str, "SPC"); X else if (ctlchar == 0177) X`009strcpy(ctlchar_str, "DEL"); X else if (ctlchar == -1) X`009strcpy(ctlchar_str, "---"); X else X`009sprintf(ctlchar_str, "%c", ctlchar); X X status = cli_get_value("BEGIN_PROMPT", &retval); X if (bad(status)) X`009strcpy(prompt_begin, ""); X else X`009strcpy(prompt_begin, retval); X X status = cli_get_value("END_PROMPT", &retval); X if (bad(status)) X`009strcpy(prompt_end, ""); X else X`009strcpy(prompt_end, retval); X X status = cli_get_value("DEFAULT_OUTPUT_FLAG", &retval); X if (!bad(status)) X`009defmode = tolower(retval`0910`093); X X status = cli_get_value("PROCESS_DEFAULT", &retval); X if (bad(status)) X`009defproc = CREATE; X else X`009defproc = ((retval`0910`093 == 'T') ? TOP : CREATE); X X status = cli_present("SWITCH_CREATE"); X switch_create = !bad(status); X X status = cli_present("FLOW_CONTROL"); X flow_control = !bad(status) `124`124 uw; X X status = cli_get_value("DELETE_CHARACTER", &retval); X if (bad(status)) X`009delete_char = 0177; X else X`009sscanf(retval, "%d", &delete_char); X if (delete_char < 0 `124`124 delete_char > 0177) `123 X`009printf("`091Illegal delete character (%d); using DEL instead`093\n", X`009 delete_char); X`009delete_char = 0177; X `125 X status = cli_get_value("AUTO_STUFF_STRING", &retval); X if (bad(status)) X`009def_stuff_len = 0; X else `123 X`009strcpy(def_stuff_buf, retval); X`009if (strlen(retval) > 0) X`009 strcat(def_stuff_buf, "\015"); X`009def_stuff_len = strlen(def_stuff_buf); X `125 X X status = cli_present("RECORD"); X recording = !bad(status); X if (recording) `123 X`009status = cli_get_value("RECORD", &retval); X`009if (bad(status)) `123 X`009 strcpy(record_file, "BOSS.RECORD"); X`009`125 else `123 X`009 strcpy(record_file, retval); X`009`125 X `125 X status = cli_present("PLAYBACK"); X playback = !bad(status); X if (playback) `123 X`009status = cli_get_value("PLAYBACK", &retval); X`009if (bad(status)) `123 X`009 strcpy(playback_file, "BOSS.RECORD"); X`009`125 else `123 X`009 strcpy(playback_file, retval); X`009`125 X `125 X status = cli_present("GEAR"); X if (!bad(status)) `123 X`009status = cli_get_value("GEAR", &retval); X`009if (!bad(status)) `123 X`009 char *cp = retval; X`009 while (*cp) `123 X`009`009*cp = tolower(*cp); X`009`009cp++; X`009 `125 X`009 if (!strncmp(retval, "infinite", strlen(retval))) `123 X`009`009printf("`091Boss: no delays in playback`093\n"); X`009`009gear = -1.0; X`009 `125 else `123 X`009`009gear = atof(retval); X`009`009if (gear <= 0.0) `123 X`009`009 printf("`091Boss: bad /GEAR value, assuming 1.0`093\n"); X`009`009 gear = 1.0; X`009`009`125 X`009 `125 X`009`125 X `125 X status = cli_present("LOCK"); X keyboard_locked = !bad(status); X X status = cli_present("LOG"); X auto_log = !bad(status); X/* Ensure logfile prefix gets set up whether or not there's autolog */ X strcpy(log_file_prefix, "BOSS"); X log_file_prefix_len = 4; X if (auto_log) `123 X`009status = cli_get_value("LOG", &retval); X`009if (bad(status)) `123 X`009 strcpy(log_file_prefix, "BOSS"); X`009 log_file_prefix_len = 4; X`009`125 else `123 X`009 /* watch out for overflow, need room for "x.log" */ X`009 log_file_prefix_len = strlen(retval); X`009 if (log_file_prefix_len >= sizeof(log_file_prefix) - 5) `123 X`009`009printf("`091Boss: log file prefix too long, ignored`093\n"); X`009`009strcpy(log_file_prefix, "BOSS"); X`009`009log_file_prefix_len = 4; X`009 `125 else `123 X`009`009strcpy(log_file_prefix, retval); X`009 `125 X`009`125 X `125 X X status = cli_present("QUIT_ON_IDLE"); X synchr_quit = !bad(status); X X status = SYS$TRNLNM(0, &d_lnm_file_dev, &d_boss_term, 0, &trnlnm_item); X if (bad(status)) X`009strcpy(trnlnm_string, "VT100"); X else X`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X if (strcmp(trnlnm_string, "VT100") == 0) `123`009/* VT100 */ X`009clr = "\033`091r\033`0914l\033`091H\033`091J";`009/* Clear screen reset V scroll */ X`009bos = "\033`091r\033`0914l\033`09199;1H\n";`009/* Go to bottom of screen V */ X`009ceol = "\033`091K";`009/* Clear to end-of-line */ X`009ceoln = "\033`091K\r\n";`009/* Clear to end-of-line and newline */ X `125 else if (strcmp(trnlnm_string, "VT52") == 0) `123`009/* VT52 */ X`009clr = "\033H\033J"; X`009bos = "\033Y7 \n"; X`009ceol = "\033K"; X`009ceoln = "\033K\r\n"; X `125 else if (strcmp(trnlnm_string, "ADM3A") == 0) `123`009/* ADM3A */ X`009clr = "\032"; X`009bos = "\033=7 \n"; X`009ceol = " \010\010\010"; X`009ceoln = " \r\n"; X `125 else `123`009`009`009/* UNKNOWN */ X`009clr = "\r\n"; X`009bos = "\r\n"; X`009ceol = ""; X`009ceoln = "\r\n"; X `125 X`125 X Xint Xstart_up() X`123 X long int status, j, n; X char nname`09130`093, output_flags`09130`093, stuff_flag, odefmode; X X cur = -1; X if (!uw) X`009input_state = PENDING; X init = 1; X X status = cli_present("START_PROCESS"); X if (!bad(status)) `123 X`009stuff_flag = 1; X`009j = 0; X`009while (j < 30 && !bad(cli_get_value("START_PROCESS", &retval))) `123 X`009 if (strlen(retval) != 1) X`009`009break; X`009 nname`091j`093 = toupper(retval`0910`093); X`009 if (nname`091j`093 < first_name `124`124 nname`091j`093 > last_name) X`009`009break; X`009 j++; X`009`125 X`009n = j; X`009j = 0; X`009while (j < n && !bad(cli_get_value("OUTPUT_FLAGS", &retval))) `123 X`009 output_flags`091j`093 = tolower(retval`0910`093); X`009 j++; X`009`125 X`009while (j < n) `123 X`009 output_flags`091j`093 = defmode; X`009 j++; X`009`125 X`009for (j = 0; j < n; j++) `123 X`009 if (stuff_flag) `123 X`009`009status = cli_get_value("STUFF_STRING", &retval); X`009`009if (bad(status)) `123 X`009`009 stuff_flag = 0; X`009`009 strcpy(stuff_buf, ""); X`009`009`125 else `123 X`009`009 strcpy(stuff_buf, retval); X`009`009 if (strlen(retval) > 0) X`009`009`009strcat(stuff_buf, "\015"); X`009`009`125 X`009 `125 X`009 odefmode = defmode; X`009 defmode = output_flags`091j`093; X`009 status = mov_to(nname`091j`093, 0, stuff_buf, defproc); X`009 defmode = odefmode; X`009 if (bad(status)) X`009`009break; X`009 input_state = NORMAL; X`009`125 X `125 X init = 0; X for (j = 0; j < nproc; j++) X`009if (name`091j`093 > 0) X`009 post_pty_reads(j); X`125 X Xmain() X`123 X int exit_handler`0914`093 = `1230, quit, 0, &st`125; X X process_command_line(); X check(SYS$DCLEXH(&exit_handler));`009/* Define Exit handler (quit) */ X if (ctlchar >= 0 && ctlchar < 040) X`009printf("Begin BOSS %s\nType control-%c control-h for information\n", X`009 VERSION, tolower(ctlchar + 0100)); X else if (ctlchar < 0) X`009printf("Begin BOSS %s\n", VERSION); X else X`009printf("Begin BOSS %s\nType %s control-h for information\n", X`009 VERSION, ctlchar_str); X initialize(); X if (playback) `123 X`009/* playback mode: feed data from record file to tt_srv() */ X`009/* keep checking playback - tt_srv ASTs may reset it! */ X`009int i, j; X`009char buf`09180`093; X`009char *endbufp = &buf`09180`093; X X`009tiosb.stats = SS$_NORMAL;`009/* fool tt_srv */ X`009while (1 == 1) `123 X`009 if (!playback) X`009`009break; X`009 i = read(playback_fd, &input_char, 1); X`009 if (!i) X`009`009break; X`009 if (input_char != DELAY_ESC) `123 X`009`009/* normal char, process */ X`009`009tt_srv(FALSE); X`009 `125 else `123 X`009`009/* the escape char: read more into buf */ X`009`009i = read(playback_fd, &buf, 1); X`009`009if (!i) X`009`009 break; X`009`009if (buf`0910`093 == DELAY_ESC) `123 X`009`009 /* double escape: feed one */ X`009`009 input_char = DELAY_ESC; X`009`009 tt_srv(FALSE); X`009`009`125 else if (buf`0910`093 != '\n') `123 X`009`009 /* read a delay spec */ X`009`009 int delay; X`009`009 char *bufp = &buf`0911`093; X`009`009 while ((i = read(playback_fd, bufp, 1)) && (*bufp != '\n')) `123 X`009`009`009bufp++; X`009`009`009if (bufp == endbufp) `123`009/* overflow */ X`009`009`009 i = 0; X`009`009`009 break; X`009`009`009`125 X`009`009 `125 X`009`009 if (!i) X`009`009`009break;`009/* eof or overflow: error */ X`009`009 *bufp = '\0'; X`009`009 if (gear >= 0.0) `123`009`009/* ignore delay if gear<0 */ X`009`009`009delay = atoi(buf);`009/* get in 0.1 sec units */ X`009`009 delay = (int) (delay * 100.0 / gear); X`009`009`009msleep(delay); X`009`009 `125 X`009`009`125 X`009 `125 X`009`125`009`009`009/* end while */ X`009close(playback_fd); X`009/* playback ended, switch to interactive mode if no quit yet */ X`009playback = 0; X`009sprintf(buf, "%s`091Boss: playback ended`093%s", bos, ceoln); X`009term_msg(buf); X`009/* AST on real terminal already outstanding */ X`009/* Unlock keyboard, fall through into interactive mode */ X`009keyboard_locked = FALSE; X `125`009`009`009`009/* end if (playback) */ X /* Normal mode: driven by ASTs to tt_srv() */ X sys$hiber(); X`125 $ CALL UNPACK BOSS.C;278 759145853 $ create/nolog 'f' Xmodule boss_cld Xdefine verb boss X qualifier command_character, negatable, default, X value(default="28",type=$number) X qualifier delete_character, nonnegatable, default, X value(default="127",type=$number) X qualifier start_process, nonnegatable, X value(required,list) X qualifier stuff_string, nonnegatable, X value(required,list) X qualifier output_flags, nonnegatable, X value(required,list,type=output_flag) X qualifier auto_stuff_string, negatable, X value(required) X qualifier begin_prompt, negatable, X value X qualifier end_prompt, negatable, default, X value(default="> ") X qualifier default_output_flag, nonnegatable, X value(type=output_flag) X qualifier switch_create, negatable X qualifier process_default, nonnegatable, default, X value(required,type=process_type) X qualifier flow_control, negatable X qualifier uw, negatable X qualifier record, nonnegatable, X value(type=$outfile) X qualifier playback, nonnegatable, X value(type=$infile) X`009qualifier gear, nonnegatable, X`009`009value(default="1.0") X`009qualifier log, nonnegatable, X`009`009value X`009qualifier lock, negatable X`009qualifier quit_on_idle X Xdisallow (record and playback) Xdisallow (lock and not playback) X Xdefine type output_flag X keyword b X keyword o X keyword p X keyword w X Xdefine type process_type X keyword top_level X keyword subprocess, default $ CALL UNPACK BOSS_CLD.CLD;33 2084663964 $ create/nolog 'f' X$! Procedure for compiling and linking BOSS. X$! X$ cc boss X$ set command/object boss_cld X$ link/notraceback boss,boss_cld,sys$input/opt Xsys$library:vaxcrtl/share $ CALL UNPACK BOSS_BUILD.COM;2 855795594 $ create/nolog 'f' X$! Procedure for installing BOSS. This goes into the system startup file. X$! X$ boss_dir = "usr:`091utility`093"`009! Edit to point to where BOSS.EXE resi Vdes X$ install = "$install/command_mode" X$ if f$file("''boss_dir'boss.exe","known") then install delete 'boss_dir'bo Vss X$ install create 'boss_dir'boss/priv=(phy_io,oper)/header/open/shared $ CALL UNPACK BOSS_INSTALL.COM;1 1029728184 $ v=f$verify(v) $ EXIT $! ------------------ CUT HERE ----------------------- $ v='f$verify(f$trnlnm("SHARE_VERIFY"))' $! $! This archive created by VMS_SHARE Version 7.1-004 3-AUG-1989 $! On 30-APR-1993 15:12:23.37 By user KARNEY $! $! This VMS_SHARE Written by: $! Andy Harper, Kings College London UK $! $! Acknowledgements to: $! James Gray - Original VMS_SHARE $! Michael Bednarek - Original Concept and implementation $! $!+ THIS PACKAGE DISTRIBUTED IN 6 PARTS, TO KEEP EACH PART $! BELOW 54 BLOCKS $! $! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER $! AND EXECUTE AS A COMMAND PROCEDURE ( @name ) $! $! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING: $! 1. BOSS.README;25 $! 2. BOSS.HLP;97 $! 3. BOSS.C;279 $! 4. BOSS_CLD.CLD;33 $! 5. BOSS_BUILD.COM;2 $! 6. BOSS_INSTALL.COM;1 $! $set="set" $set symbol/scope=(nolocal,noglobal) $f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID")) $e="write sys$error ""%UNPACK"", " $w="write sys$output ""%UNPACK"", " $ if f$trnlnm("SHARE_LOG") then $ w = "!" $ if f$getsyi("version") .ges. "V4.4" then $ goto START $ e "-E-OLDVER, Must run at least VMS 4.4" $ v=f$verify(v) $ exit 44 $UNPACK: SUBROUTINE ! P1=filename, P2=checksum $ if f$search(P1) .eqs. "" then $ goto file_absent $ e "-W-EXISTS, File ''P1' exists. Skipped." $ delete/nolog 'f'* $ exit $file_absent: $ if f$parse(P1) .nes. "" then $ goto dirok $ dn=f$parse(P1,,,"DIRECTORY") $ w "-I-CREDIR, Creating directory ''dn'." $ create/dir 'dn' $ if $status then $ goto dirok $ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped." $ delete/nolog 'f'* $ exit $dirok: $ w "-I-PROCESS, Processing file ''P1'." $ define/user sys$output nl: $ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1' PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET( SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name"); buff:=CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(buff)) ;LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION( BEGINNING_OF(buff));g:=0;LOOP EXITIF MARK(NONE)=END_OF(buff);x:= ERASE_CHARACTER(1);IF g = 0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x= "V" THEN APPEND_LINE;MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF; IF x="+" THEN g:=1;ERASE_LINE;ENDIF;ELSE IF x="-" THEN g:=0;ENDIF;ERASE_LINE; ENDIF;ENDLOOP;p:="`";POSITION(BEGINNING_OF(buff));LOOP r:=SEARCH(p,FORWARD); EXITIF r=0;POSITION(r);ERASE(r);COPY_TEXT(ASCII(INT(ERASE_CHARACTER(3)))); ENDLOOP;o:=GET_INFO(COMMAND_LINE,"output_file");WRITE_FILE(buff,o); ENDPROCEDURE;Unpacker;EXIT; $ delete/nolog 'f'* $ CHECKSUM 'P1' $ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT $ e "-E-CHKSMFAIL, Checksum of ''P1' failed." $ ENDSUBROUTINE $START: $ create/nolog 'f' XThis is BOSS version 4.3 (June 2, 1992). It consists of 6 files X BOSS.README`009 This file X BOSS.HLP`009 The user help file X BOSS.C`009 The source code X BOSS_CLD.CLD The command language definitions X BOSS_BUILD.COM The procedure for compiling and linking BOSS X BOSS_INSTALL.COM The procedure for installing BOSS X XBOSS requires that pseudo TTY (PTY) drivers be installed on your system. XThis should be the latest version posted to INFO-VAX by Kevin Carosso in XAugust 1988. This is recommended version for both VMS 4.x and VMS 5.0. XContact me if you need a copy of the PTY drivers. Alternatively, BOSS Xwill run with the FTdriver. It is currently set up to do so, but can Xuse the PY/TW driver combo instead; just edit the compile time conditional. X XIf you plan to use BOSS/UW (to get multi-window operation on a Macintosh), Xyou will need the UW terminal emulator. I can send you that too. X XYou should edit BOSS_INSTALL.COM to refer to the directory where BOSS.EXE Xresides. BOSS should be installed with both PHY_IO and OPER privileges. XYou can get by without these privileges--see the comments in BOSS.C. X XBOSS needs to be defined as a foreign command, i.e., X $ BOSS == "$:`091`093BOSS" XBOSS.HLP tells the user to do X $ SETUP BOSS Xbefore running BOSS. SETUP on our system runs a .COM file which does the Xnecessary initialization for various utilities. You will probably need to Xedit BOSS.HLP to insert the incantation appropriate for your site. XBOSS.HLP should of course be installed in some easily accessible help Xlibrary. Something like X $ LIBRARY/HELP/REPLACE HLP$LIBRARY_1 BOSS Xshould do the trick. X X Charles Karney `032 X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2160 X X---------------------------------------------------------------------------- V-- X XThe remainder of this file is specific to people running BOSS/UW. X XThe user documentation is in HELP BOSS Windows and its subtopics. X XYou will get a separate mailing containing the three files X UNIX-UW-42.HQX`009The UW terminal emulator and documentation X UWPROTO.TXT`009`009Internal documentation on UW protocols X MACMOUSE.EL`009`009Mouse support for Gnu Emacs X XUNIX-UW-42.HQX should be downloaded to a Mac as a text file and run through Xthe BinHeX and Packit programs to give uw (the terminal emulator) and Xuw.doc (the documentation in MacWrite format). X XUWPROTO.TXT describes the protocol used by UW and BOSS/UW. Can be ignored Xif you like. X XIf you have Gnu Emacs: X XMACMOUSE.EL should be moved to EMACS_LIBRARY:`091LISP`093. XAdd a uw entry in EMACS_LIBRARY:`091ETC`093 with: X X# Macintosh/UW termcap (same as Mac without the cs, and has km = meta) Xd0`124uw`124uw-am`124unix-windows:\ X`009:cr=`094M:do=`094J:nl=`094J:bl=`094G:co#80:li#24:cl=50`094O\E`091;H\E`09 V12J:\ X`009:le=`094H:bs:am:cm=5\E`091%i%d;%dH:nd=2\E`091C:up=2\E`091A:\ X`009:ce=3\E`091K:cd=50\E`091J:so=\E`0917m:se=\E`091m:us=\E`0914m:ue=\E`091m: V\ X`009:md=\E`0911m:mr=\E`0917m:mb=\E`0915m:me=\E`091m:is=\E`0911;24r\E`0914l\E V`09124;1H:\ X`009:rs=\E>\E`091?3l\E`091?4l\E`091?5l\E`091?7h\E`091?8h:\ X`009:ks=\E=\E`091?1h:ke=\E>\E`091?1l:\ X`009:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kb=`094H:\ X`009:ho=\E`091H:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:ta=`094I:pt:sr=5\EM:vt#3:xn: V\ X`009:ic=7\E`0911@:dc=7\E`0911P:al=9\E`0911L:dl=9\E`0911M:\ X`009:sc=\E7:rc=\E8:\ X`009:IC=7\E`091%d@:DC=7\E`091%dP:AL=3*\E`091%dL:DL=3*\E`091%dM:km: X XPostscript: X XI still prefer VersaTerm PRO to UW, even though it doesn't have multi- Xwindow support. There are too many VersaTerm features that I need which Xare absent in UW. X XI've only implemented the most basic level of UW service under BOSS X(protocol 1 in UWPROTO.TXT). The next level allows windows to be retitled Xfrom the VAX, as well as setting many of the other attributes of windows. XThis will most likely not get implemented, unless multi-window support Xappears in VersaTerm. X XThe main reason for implementing the UW features in BOSS was to show that Xthe Macintosh can provide a multi-window enviroment for the VAXes. Now we Xhave to get Lonnie Abelbeck to modify VersaTerm to support the UW Xprotocol... X XNote that Meshugena-term on Amiga, as well as UW on Amiga, support the UW Xprotocol. $ CALL UNPACK BOSS.README;25 524441163 $ create/nolog 'f' X1 BOSS XBOSS is an interactive job controller. It lets you run several interactive Xjobs simultaneously. Before running BOSS put X X $ SETUP BOSS X Xinto your login.com file. In order to run BOSS type X X $ BOSS X XBOSS can operate in one of two modes: X* regular mode. This works with any terminal. See subtopic Description for X an overview. X* multi-window mode; this ONLY works with a Macintosh running the UW termina Vl X emulator. See subtopic Windows for an overview and further details. X2 Description XBOSS lets you create up to 8 processes on a VAX/VMS system. Each process is Xidentified by a single letter (A thru Z). This letter is used in the Xprocess name and in the DCL prompt. At most one of these processes is X`096current'. What you type is sent to that process, and output from that Xprocess is sent to your terminal. A process which is not current can run Xbut normally cannot do output. (What happens to the output is governed by Xthe output flag for a particular process. See topic Output_flags.) You Xusually switch between processes by typing control-\ followed by the Xidentifying letter. It is also possible to have have of your processes Xinitiate the switch. (See topic Communicating.) X XYou can run any program under BOSS. For example, you might X run Emacs or EVE in process E X SET HOST to another machine 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 `096logout') and swit Vch Xto 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 XHowever, you can GET Boss to remember things on your screen by giving the XControl-J and control-I commands, which cause BOSS to remember what is typed Xto your screen for the last 4000 characters and restore it when returning to Xyour process. You can also get BOSS to record output to a virtual terminal Xin a file BOSS.LOG (where is the 1-character process name) with the Xcontrol-L command. X XBOSS uses needs to know the escape sequences for clearing your screen, etc. XBy default, it uses the VT100 sequences which work for a wide range of Xterminals. See topic Terminal_types. X2 Commands `032 XUsually, all commands to BOSS begin with the command character which by Xdefault is C-\ (control-\). The command character can be changed by using Xthe /COMMAND_CHARACTER qualifier to BOSS. The command character is not Xrequired when there is no current process (i.e., initially and immediately Xafter logging out of a process). In that case the command character is Xoptional. X XThe commands are: X X C-h (or BS) Print command summary X C-z Quit (asking confirmation if there are processes) X C-x Quit after the last process has terminated X a Switch to process labeled A (and similarly with a thru z) X A Clear screen and then switch to process A X C-n a Create new process A as a subprocess (C-n A clears screen first) X C-t a Create process A at top level (C-t A clears screen first) X C-k Kill the current process (asks for confirmation) X C-b Buffer output for this process X C-o Discard output for this process X C-p Print output from this process X C-w Stop output from this process X C-i Toggle buffering active output X C-j Toggle keeping buffer for more than 1 X process transition X C-l (ell) Toggle logging to BOSSn.LOG. Separate logfiles to X each process are kept and logging is of what is X sent to the pseudoterminal, not the real one, so X you can log a process that is in discard-output mode. X C-v Toggle logging to BOSSn.LOG. Similar to C-L except X`009`009that C-L logging suspends the logfile write when X`009`009toggled off again, and C-V logging closes the log X`009`009file when toggled off. X C-e Toggle logging. This is similar to C-l except that it X `009`009closes the logfile when it stops logging. Thus you X`009`009can use C-l when you need to log several items but X`009`009want to skip the material between, keeping all the X`009`009logged data in one file. Use control-E to log a bit X`009`009of a session which you can then examine in a second X`009`009session, without having to leave BOSS. Note that X`009`009logging must be on to close the file. X C-g n Allows saving of n lines of buffered output (needs to be X in C-i C-j mode) and replaying them into the next X process you switch to, enabling cut/paste. X +`009 Enter command mode for one line X ? List processes and output flags X (* means current, +/- means waiting for output) X C-\ Sends the command character to the current process X DEL Do nothing X other Sound the bell on the terminal X X Command mode allows one command to be entered. This is done with a Xnormal $QIOW, so should be used for setup, as it may cause character XASTs to be lost if used in heavy activity. A number of commands are Xsupported, short to minimize time needed to enter them: X X Schars Sets current process to get chars (up to 7 of them) X`009when the process is switched to. A common use will be X`009S`094W, where "`094W" means the control-W character, which X`009gets many fullscreen applications to repaint the screen. X Gchars Like Schars but sets the prefix for all processes. The X`009prefix is initially nonexistent. X Enumber Causes the terminal buffer to only write "number" characters X`009to the screen on a process switch where `094I and `094J modes X`009are active. Otherwise the entire saved buffer is dumped X`009on each switch, which may be more than is desired. The X`009value is clamped between 100 and the buffer size. Enumber X`009affects only the current process. X Gnumber Like Enumber, but resets the output size for all processes. X X`009The Enumber and Gnumber commands are designed to allow one to X`009buffer a large number of characters, but only display a X`009smaller number on context switches. Reissuing the commands X`009with a larger value of "number" will allow the rest to be X`009seen. Also, if `094I`094J mode is not in use, the entire buffer X`009is displayed as was the case in earlier versions of BOSS. X X2 Qualifiers XWhen starting BOSS you can provide the following qualifiers: X X/COMMAND_CHARACTER X /COMMAND_CHARACTER=num X Default: /COMMAND_CHARACTER=%O34 (i.e., C-\) X XUse the character whose ASCII code is num as the command character instead Xof C-\. E.g., X BOSS/COMMAND_CHARACTER=%X1F ! set command character to C-_ X BOSS/COMMAND_CHARACTER=%O37 ! the same X BOSS/COMMAND_CHARACTER=31 ! the same X BOSS/COMMAND_CHARACTER='F$CVSI(0,6,"_")' ! the same X BOSS/COMMAND_CHARACTER='F$CVSI(0,8,"`096")' ! set to `096 (backquote) XRepeating the command character twice sends the character to the current Xprocess. C-z is disallowed as a command character since otherwise you Xwouldn't be able to quit. X X/START_PROCESS X /START_PROCESS=(process-1,process-2,...) X XBOSS immediately starts up the specified processes. E.g., X BOSS/START_PROCESS=A Xstarts process A. You are left in the last process specified; e.g., X BOSS/START_PROCESS=(E,D) Xstarts E and D and sets D to be the current process X X/STUFF_STRING X /STUFF_STRING=(string-1,string-2,...) X XThis qualifier is processed in parallel with /START_PROCESS. string-n is Xsent the process-n when it is started. A carriage return is added to the Xstring unless the string is empty. If the /STUFF_STRING list is shorter Xthan the /START_PROCESS list, then nothing is sent to the remaining Xprocesses. E.g., X BOSS/START=(E,D)/STUFF=EMACS Xstarts process E runs Emacs in it. Then BOSS starts process D (and sends Xnothing to it). To send more than one command to a process, you can do, Xe.g., X BOSS/START=(B,B)/STUFF=("SHOW TIME",FINGER) Xwhich start process B and sends runs both SHOW TIME and FINGER. (Or else Xyou can construct a DCL string with an imbedded carriage return. X X/AUTO_STUFF_STRING X /AUTO_STUFF_STRING=string X XThis specifies a string to stuff into each newly created subprocess. A Xcarriage return is added to the string unless the string is empty. This Xgets sent to the subprocess before the strings specified by /STUFF_STRING Xor BOSS$STUFF. Top-level processes are unaffected by this qualifier. XThere are three applications where this would be useful. (1) If BOSS is Xnot installed with PHY_IO privilege (so that subprocesses don't Xautomatically inherit the parents terminal type), then use, e.g., X BOSS/AUTO_STUFF="SET TERM/VT100" X(2) If you are a privileged used and you want to be able to select any of Xyour authorized privileges in each subprocess, but you don't want them Xturned on by default, then use X $ DEFPRIV = F$GETJPI("","PROCPRIV") X $ SET PROCESS/PRIV=ALL X $ BOSS/AUTO_STUFF="SET PROCESS/PRIV=(NOALL,''DEFPRIV')" XThis way each subprocess will have your standard set of current and Xauthorized privileges. (Note that the authorized privileges for a Xsubprocess are set from the current privileges of its parent.) X(3) You want to turn off some classes of broadcasts in subprocesses. X BOSS/AUTO_STUFF="SET BROAD=NOSHUTDOWN" XYou will normally still receive such broadcasts when BOSS re-broadcasts Xthe broadcasts it receives to the current process. However, you will only Xreceive one copy of each broadcast. See also subtopic Broadcasts. X X/OUTPUT_FLAGS X /OUTPUT_FLAGS=(flag-1,flag-2,...) flag-n is one of b, o, w, p X XThis qualifier is processed in parallel with /START_PROCESS. The output Xflag for process-n is set to flag-n. If the /OUTPUT_FLAGS list is shorter Xthan the /START_PROCESS list, then the output flags for the remaining Xprocesses are set to the default. X X/DEFAULT_OUTPUT_FLAG X /DEFAULT_OUTPUT_FLAG=flag (one of b, o, w, p) X Default: /DEFAULT_OUTPUT_FLAG=b X XThis sets the default output flag. See topic Output_flags. X X/BEGIN_PROMPT X /BEGIN_PROMPT=string X Default: /NOBEGIN_PROMPT X XThis specifies the part of the DCL prompt which appears before the process Xlabel. E.g., X BOSS/BEGIN_PROMPT="--"/END_PROMPT=">> " Xgives you DCL prompts of the form "--Q>> ". X X/END_PROMPT X /END_PROMPT=string X Default: /END_PROMPT="> " X XThis specifies the part of the DCL prompt which appears after the process Xlabel. X X/SWITCH_CREATE X /SWITCH_CREATE X Default: /NOSWITCH_CREATE X XBy default, you have to create a process with either C-\ C-n x or C-\ C-t Xx. If /SWITCH_CREATE is set, then switching to nonexistent process Xcreates it as a subprocess. (I.e., C-\ x is equivalent to C-\ C-n x). If Xyou always want /SWITCH_CREATE set, then put X $ setup boss X $ boss == "''boss'/switch_create" Xinto your LOGIN.COM file. X X/PROCESS_DEFAULT X /PROCESS_DEFAULT=process-type (one of SUBPROCESS and TOP_LEVEL) X Default: /PROCESS_DEFAULT=SUBPROCESS X XThis governs the types of the processes created by /START_PROCESS, process Xswitching initiated by BOSS$SWITCH. (I.e., all process creation except for Xvia C-\ C-n x and C-\ C-t x.) X X/FLOW_CONTROL X /FLOW_CONTROL X Default: /NOFLOW_CONTROL X XNormally, everything you type is passed on to the current process. This Xincludes the flow-control characters control-s and control-q. This results Xin some delay in these characters being acted upon. Your terminal may Xtherefore receive many additional characters after a C-s is typed, causing Xyou to lose information off the top of your screen or your terminal's input Xbuffer to overflow. With X BOSS/FLOW_CONTROL XC-s and C-q are intercepted by the terminal driver and used as flow- Xcontrol. This cause C-s to be acted on more promptly. The drawback is Xthat you can never send C-s and C-q to your program. This breaks certain Xprograms, notably Emacs, which need to be able to receive all the ASCII Xcharacters. A second drawback is that once the output is stopped with C-s, Xonly a C-q can get it going again. You can't interrupt it with a C-y as Xyou can normally. (This is because BOSS/FLOW_CONTROL only treats C-s and XC-q as special. C-y and C-c are treated as ordinary characters.) X X/DELETE_CHARACTER X /DELETE_CHARACTER=num X Default: /DELETE_CHARACTER=%O177 (i.e., DEL) X XUse the character whose ASCII code is num as the delete character instead Xof DEL. This is useful on some terminals with weird keyboards. E.g., on Xsome ADM terminals, the delete key is shift-underscore. If you do X BOSS/DELETE_CHARACTER='F$CVSI(0,8,"_")' Xthen underscore and delete are interchanged. (I.e., the underscore key Xsends a delete to your program, and the shift-underscore key sends an Xunderscore to your program.) X X/UW X /UW X Default: /NOUW X XEnter BOSS in multi-window mode. You must be running the UW multi-window Xterminal emulator on a Macintosh computer. See topic Windows for more Xinformation. X X/RECORD X /RECORD`091=filespec`093 X Default: /RECORD=boss.record X XGenerate a file (boss.record by default) containing the keystrokes entered Xat the physical terminal, interspersed with timing information for later Xplayback. X`032 XThe timing is recorded as delay specifications of the form \, Xwhere is the delay in 100 millisecond units, and is a linefeed Xcharacter (hex 0A). Delays between keypresses that are less than a certain Xthreshold (currently 0.3 sec) will not be recorded. A "\" occurring as Xnormal character will be written to the session record file as "\\". X X/PLAYBACK X /PLAYBACK`091=filespec`093 X Default: /PLAYBACK=boss.record X`032 XPlayback a previously recorded session, see /RECORD. Upon reaching the end Xof the record file, Boss will switch from playback to interactive mode. The Xswitch to interactive will also happen if there is keyboard input, but see Xthe /LOCK qualifier for a way to prevent this. X XNB: in order to duplicate exactly the environment in which the session X is played back, you must make sure that Boss is started with the X same qualifiers as during recording, except for the playback X specific ones of course. X XSee also /GEAR to change the speed with which the session is replayed. X X/GEAR X /GEAR=I`091nfinite`093 or X /GEAR= X Default: /GEAR=1.0 X XUse /GEAR with the playback mode to speed up (or slow down) the replay. The Xspecified will be used as a multiplier for the delay specifiers Xencountered in the session record file. The default is 1.0, Xi.e. playback in real time. The value must be positive; specifying XI`091nfinite`093 will have the effect that delays are ignored completely. X`032 X/LOCK X /LOCK X Default: /NOLOCK X XLock the keyboard during a playback session. At the end of the record file, Xthe keyboard will be unlocked. X`032 XYou will need this if the applications that run issue commands to the Xterminal that cause the terminal to respond all by itself, for instance a X'set terminal/inquire' on DCL level, or if you don't want the user to Xinterfere with a playback session. In the absence of /LOCK, boss will Xterminate a playback session and switch to interactive mode as soon as it Xreceives data from the physical terminal. X X/QUIT_ON_IDLE X /QUIT_ON_IDLE X Default: /NOQUIT_ON_IDLE X`032 X Perform an automatic quit if there are no more processes active. This is X the equivalent of the control-x command (help topic "Commands"). X X/LOG X /LOG= X Default: /LOG=BOSS X XMake logging the default action when creating processes. See the description Xof the control-l command (help topic "Commands"). If the optional X is given, used that as the first part of the log file Xname, else use the string "BOSS" instead. The log file name will consist of Xthis prefix, followed by a 1-character name of the process and the string X".LOG". X2 Terminal_types XWhen switching processes, BOSS tries either to clear the screen or to move Xto the bottom of the screen. By default, it uses VT100 escape sequences for Xthese operations. However, if you define the logical name BOSS$TERM to be Xthe name of some other terminal, then it will use the escape sequence for Xthat terminal. X XE.g., if you're using an ADM3A terminal, you should do X $ DEFINE/NOLOG BOSS$TERM ADM3A Xbefore starting BOSS. (ADM3A users would probably also want to set the Xdelete character to underscore. See topic /DELETE_CHARACTER.) X XAt present BOSS only knows about three types of terminals: VT100, VT52, XADM3A, and UNKNOWN. The last choice makes minimal assumptions about the Xterminal, and should always give a reasonable display. X2 Process_types XBOSS deals with two types of processes: subprocesses and top-level Xprocesses. X XSubprocesses are what you get with the DCL command SPAWN. They inherit Xsymbols and logical names from the parent process (i.e., BOSS itself) at Xcreation time. The resources it uses count against the parent's quotas. XThe number of subprocesses is governed by your subprocess quota. XSubprocesses share the job logical name with the parent process. This gives Xa way for subprocesses to communicate with one another and with their Xparent. X XTop-level processes acts just like an entirely new login session (as though Xyou had done SET HOST 0). Indeed, you have to log in to get the process Xgoing. The resources that such processes use do not count against the Xparent's quotas. SHOW USERS will show that you are logged in multiple Xtimes. X XWhich type of process should you use? X XIn most cases subprocesses are best. These usually are quicker to get Xstarted (since you don't have to go through the login procedure again). XBOSS is able to set the process name and DCL prompt to include the process Xlabel. Synchronous switching to another process from a subprocess is Xpossible using the BOSS$SWITCH and BOSS$STUFF job logical names. X XWhen should you use a top-level process? Here are some cases: X* You need to log in as someone else. X* You need to run a large program that uses all of one of your quotas. X* You need to run with a different CLI. Log in with e.g., /CLI=SHELL. X* Your subprocess quota is too low to allow you to create subprocesses. X XType C-\ C-n a to start subprocess A; type C-\ C-t b to start top-level Xprocess B. X2 Output_flags XEach process has an output flag which may be set by C-\ followed by one of +-+-+-+-+-+-+-+- END OF PART 1 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ XC-b, C-o, C-p, or C-w (this sets the flag to b, o, p, or w, resp.). This Xflag governs what BOSS does to the output of a process which is not current. X(The current process always gets its output displayed immediately.) The Xmeanings of these settings are X X b Buffer output for this process. Output is saved in a 4k buffer. Buffer X is output when the process becomes current. The process hangs when this X buffer fills. This is useful for running a program which dribbles X output which you do not want to lose. In the process list (obtained by X C-\ ?), a - indicates that there is output ready to be displayed, and a X + indicates that the buffer is full (and the process is probably X hanging). X X o Discard output for this process. Only the most recent write will by X output when the process becomes current. This is useful for running a X program which periodically outputs some straightforward information such X as `096Processing record 103', where all you care about is the most rece Vnt X output. In the process list, + means that there is output available X (but the process is continuing to run). X X p Print output from this process. Output is output to the terminal X regardless of whether this is the current process or not. This is X useful if you need to be informed when a program completes. Also it can X be used to display status information periodically on your screen (see X subtopic Examples). X X w Stop output from this process. The process can do a single write which X will be accepted and saved by BOSS. The process will then hang when it X attempts to do the next write. In the process list + means that there X is output available (and the process is probably hanging). X XThe default output flag is b. The default can be changed by using the XDEFAULT_OUTPUT_FLAG qualifier or by issuing one of the flag setting commands Xwhen there is no current process (i.e., immediately after starting BOSS or Xafter logging out of a process). X XThe best setting of the output flag very much depends on your application. XYou will probably find the best setting to be b (the default). If one Xprocess is attempting to act synchronously with another, it may be necessary Xto set their output flags to w. However, if your synchronous switches are Xall performed via the BOSS$SWITCH mechanism, this isn't necessary since BOSS Xtemporarily sets the output flag to w on these types of process switches X(see topic Communicating). X XA potential problem with the b setting is that BOSS empties the buffer to Xyour terminal in a single operation. This may overflow your terminal's Xinput buffer (this is not a problem with a Mac running VersaTerm at 9600 Xbaud). This is not a problem if BOSS is used with the /FLOW_CONTROL Xqualifier (assuming that your terminal does flow control). X3 Examples XSuppose TIME.COM contains: X $ esc`0910,8`093=27 X $ sc = esc + "7" ! Save cursor X $ rc = esc + "8" ! Restore cursor X $ home = esc + "`091;76H" ! cursor to top right of screen X $ invert = esc + "`0917m" ! inverse video X $ revert = esc + "`091m" ! normal X $10$: X $ time = sc+home+invert+f$extract(12,5,f$time())+revert+rc X $ read/prompt="''time'"/end=43$/error=42$/time_out=0 sys$command dummy X $42$: X $ wait ::5 X $ goto 10$ X $43$: X XThis displays the time at 5 second intervals in the top right corner of Xthe screen. If this is running in a process whose output flag is p, the Xtime will displayed while in other processes. X2 Communicating XBOSS and the subprocesses under it can communicate via logical names. These Xonly work for BOSS's subprocesses, not for its top-level processes (because Xonly the subprocesses share the job logical name table with BOSS). The Xfollowing are recognized: X XBOSS$ID (in process table); BOSS defines this as the identifying letter of Xthe process. This can be used in tailoring the DCL prompt etc.; e.g., X $ set prompt "boss-''f$trnlnm("boss$id")'>" XIt can also be used to indicate to a program that it is running under BOSS. X XBOSS$SWITCH (in job table); whenever BOSS is writes output to the real Xterminal, it checks whether BOSS$SWITCH is defined. If it's defined as a Xsingle letter, BOSS will switch to that process and delete the logical name. XIf the process doesn't exist it is created as a subprocess. Thus a DCL Xprocedure can initiate a switch to process G with X $ define/job boss$switch g X $ write sys$error "" ! do some output to make BOSS wake up XThe switch takes place synchronously by setting the output flag for the Xoriginating process to w temporarily (see topic Output_flags). Both XBOSS$SWITCH and BOSS$STUFF should be defined as supervisor mode logical Xnames in the job table. They may be defined from programs with e.g., X status:=lib$set_logical('BOSS$SWITCH','D','LNM$JOB'); X XBOSS$STUFF (in job table); whenever a BOSS makes a process initiated switch. XIt stuffs the definition of BOSS$STUFF into the input stream of the process Xbeing switched to. After being used, BOSS$STUFF is deleted. X3 Examples XThe following command procedure will do a SHO DEF and leave SHO DEF in the Xrecall buffer: X $ cr`0910,8`093 = 13 X $ define/job boss$stuff "sho def''cr'" X $ define/job boss$switch 'f$trnlnm("boss$id")' X XHere's how to switch to process F and have the present job continue Xrunning: X $ define/job boss$switch f X $ char`0910,8`093 = 22 ! control-V X $ gosub out_char X $ return X $! X $out_char: ! Spit out the character X $ read/prompt='char'/end=40$/error=40$/time_out=0 sys$command dummy X $40$: return X XIf you want the present process to wait, then repeat the `096gosub out_char' Xthree times. X XReturn paths may be implemented via additional logical names. E.g., the Xprocedure that runs Emacs under BOSS does the following. X XIf Emacs isn't running (boss$emacs undefined) do X $ define/job boss$emacs 'f$trnlnm("boss$id")' Xand start Emacs. X XIf Emacs is running (boss$emacs defined) do X $ define/job boss$return_switch 'f$trnlnm("boss$id")' X $ define/job boss$switch 'f$trnlnm("boss$emacs","lnm$job")' X $ gosub out_char X $ gosub out_char X $ gosub out_char X XThe suspend-emacs function in Emacs is redefined to do the equivalent of X $ define/job boss$switch 'f$trnlnm("boss$return_switch","lnm$job")' X $ deassign/job boss$return_switch X ... X XSimilarly boss$return_stuff may be used as the string to stuff into the Xprocess on return. The edit procedure that is called on a TeX error may Xset this to the current TeX command line so that on exiting from the Xeditor the user has the input buffer prepared with the command to re-run XTeX. The user then has the option either of accepting the command (by Xtyping return) or cancelling it (with C-u). X2 Logging XTo save what gets sent to a process in a file, one can use the C-l toggle to Xtoggle creation of a logfile. These files are named BOSSn.LOG (in the Xdirectory where one was at the time of running BOSS, since they are created Xby the BOSS process), where n is the internal BOSS process number (0 to n, Xwhere the number is the process slot; usually this corresponds to the order Xof process creation). Whatever goes to the process as console output is Xlogged, even if BOSS is discarding terminal output from that process; the Xfile output is extracted (as a stream-LF file) prior to the BOSS decisions Xon what to do with the text. A C-e will close the file, and a new C-L or C- Ve Xwill open a new version, and so on. This can be very convenient for Xallowing an editor in another process to look over the log file. XNote that C-L and C-E both toggle logging. The difference is that C-L Xdoes not close the logfile, just suspends output to it, while C-E Xcloses the logfile so that a new version can be created and the version Xjust created can be examined without having to leave BOSS (or exit the Xprocess that was being logged). X2 Redisplay XC-i toggles a buffer capture mode. Its function is to save all output to a Xsession in the BOSS internal buffer (just using it as a circular buffer) Xeven if the output is also going to the terminal. Then upon switching out Xof that session and coming back in, the entire BOSS buffer gets played back. XThe net effect of this is that material that may have scrolled off the Xscreen or been lost due to fullscreen operations of another process gets put Xback, in effect recreating the screen corresponding to the process that had Xits control removed. X XDue to internal logic, the C-i toggle will allow this playback to occur once Xand delete the material, so that what gets saved and played back is what was Xwritten during the current session on the screen. That is, if I have Xprocesses A and B and have process A in C-i mode then a screen session might Xlook (very schematically) like this: X X `091in process A`093 X foo bar X mumble`032 X random messup X editing X random commands X `091Switch to process B`093 X random other messup X `091Switch to process A`093 X foo bar X mumble`032 X random messup X editing X random commands X more stuff typed to process A X and so on X `091Switch to process B`093 X other process B stuff X `091Switch to process A`093 X more stuff typed to process A X and so on X newer still process A commands X XNote that the initial "foo bar" and so on commands were played back only Xonce. X XIf it is desired to keep ALL the text as long as possible, an additional Xmode (which I called "multishot buffering" for no particularly good reason) Xcan be toggled by C-j (linefeed) after the C-\ character. In this mode, all Xof the process A commands that will fit in the BOSS save buffer are kept as Xlong as possible. (Note the BOSS buffer is not really used circularly; text Xis moved up as new text gets added once the buffer fills.) Thus, to buffer Xtext and keep it forever one needs C-i to turn on the buffering AND C-j to Xkeep the text as long as possible. Since the BOSS buffer defaults to 4096 Xcharacters this will generally completely recreate whatever was on screen. X2 Paste XA very limited (and rather kludgey) cut and paste facility exists in that, XIF BOSS is saving output from a process in its buffer (i.e., at least C-i Xmode is active), BOSS can be told to save off the last "n" lines of this Xsaved output from the current process. These are played back into the next Xprocess one switches to as though they had been typed in. Clearly this is Xnot rectangular, allows no editing (unless the lines are pulled into an Xeditor running separately in another process and then pulled to a third Xprocess), and will often not do what one wants. Hokey as it is, though, it Xcould be of some limited value, usually for transferring text to an editor. XThe number of such lines of text is limited by an internal BOSS compile time Xparameter which is in the range of 10 to 20 lines normally; this is to Xprevent unlimited garbage from being transferred and to recognize that the Xtransfer may fail if type-ahead is not sufficient. In general BOSS works Xbetter with large typeahead set in SYSGEN; I have it set to 1024 on our Xsystem, which also aids asynchronous file transfer schemes by avoiding Xcharacter loss. I recommend this also for cases where memory is not too Xtight, to avoid lots of potential synchronization issues with the pty Xdrivers. X2 Broadcasts `032 XWhen running running under BOSS, there is the potential that you will Xreceive multiple copies of the same broadcast. In order to understand what Xis going on, it is useful to distinguish 3 types of broadcast messages: X X(1) Broadcasts to a specific process. E.g., the response of the system to Xcontrol-t. These typically are sent to one of the processes under BOSS. X X(2) Broadcasts to top-level processes. E.g., mail notification. These are Xtypically sent to the process running BOSS and any top-level processes Xunder BOSS. X X(3) Broadcasts to all terminals (including pseudo terminals). E.g., Xshutdown messages. These are typically sent to the process running BOSS and Xall processes under BOSS. X XIn order to help manage broadcast messages, BOSS intercepts any broadcasts Xsent to the process running BOSS, and rebroadcasts them to the current Xprocess. The rebroadcasts are of type USER16. This allows you to shut Xthese rebroadcast out with SET BROAD=NONE or SET BROAD=NOUSER16. Control-s Xalso works to defer broadcasts. Any broadcast handlers which the current Xprocess has active will be called to process the broadcast. X XIn order to avoid getting multiple copies of the same broadcast, here's what Xyou should do: X XIn each subprocess under BOSS, disable type 3 broadcasts, i.e., do X SET BROADCAST=NOSHUTDOWN ! plus others maybe? XYou can accomplish this automatically with the /AUTO_STUFF_STRING qualifier Xto BOSS. X XIn each top-level process, disable type 2 and 3 broadcasts, i.e., do X SET BROADCAST=(NOSHUTDOWN,NOMAIL,NOQUEUE,NOPHONE) ! plus others? XThis assumes that you are logged into the top-level process under the same Xusername. If using a different username, then you wouldn't want to disable Xmost (all?) of the type 2 broadcasts. For example, we would want to permit Xmail notification. X XIn order to stop broadcasts to a particular process, do X SET BROADCAST=NONE X XThere are some drawbacks with way BOSS rebroadcasts messages: X X* There is no way of determining the original type of the broadcast was X(MAIL, PHONE, etc.). For this reason, BOSS rebroadcasts everything as XUSER16. X X* If the rebroadcast fails, because the current process has broadcasts Xdisabled, then there is no way of getting this information to the original Xsender. E.g., if you SET BROAD=NONE is a process under BOSS and someone Xtries to PHONE you, he will not be notified that you're not getting his Xconnection requests. X2 Playback XWith the aid of the /RECORD and /PLAYBACK qualifiers it is possible to let XBOSS replay a session for you. However, this is a crude and rather limited Xfacility. X XIn particular, you should be aware of the following when executing a Xplayback. X XIt's easy for BOSS to overflow the pseudoterminal with data from the record Xfile. This may be expected to happen if you select a high /GEAR value of Xcourse, or if you edit a record file and change the delay specifiers. But Xeven if the system load is a bit higher during playback than it was when the Xsession was recorded, you may get into trouble. X `032 XProblems manifest themselves in several ways: X - BOSS feeds more data to the pseudoterminal than will fit in the typeahea Vd X buffer. In this case you will get DATAOVERUN warning messages on your X terminal, and some characters will be lost. X This problem may perhaps be solved in the future when BOSS learns how X to handle thse overflow conditions properly. X - Commands for BOSS in the record stream may get acted upon before the X current process has completed processing its data. For example, a X process switch may be executed by BOSS, when the current process is X still active processing the data in its typeahead buffer. X - Applications run in one of the processes controlled by BOSS may decide X to throw away typeahead. If the timing is different, this may happen at X another place in the input stream than during recording. X2 New_features X(1.7) Incompatible change: C-\ C-n x required to create a new process. Use XBOSS/SWITCH_CREATE to get the old behavior (where C-\ x would create process XX if it doesn't exist). X X(1.7) C-\ C-t x creates a process at top level. See topic Process_types. X X(1.8) BOSS accepts various qualifiers when it starts. These control the Xcommand character, DCL prompt string, etc. They also can be used to tell XBOSS to start various processes. See topic Qualifiers. X X(1.9) Broadcast messages sent to the process running BOSS are trapped and Xrebroadcast to the current process. See topic Broadcasts. X X(2.0) /DELETE_CHARACTER=num added to allow interchange of some character Xwith delete. See topic /DELETE_CHARACTER. X X(2.1) Logical name BOSS$TERM looked at to determine terminal type. See Xtopic Terminal_types. X X(2.2) BOSS fixed to work with new release of pseudo TTY drivers. X X(2.4) /FLOW_CONTROL added to allow flow control by the top-level process. XSee topic /FLOW_CONTROL. X X(2.5) /PROCESS_DEFAULT=process-type added to get top-level processes Xcreated by default. See topic /PROCESS_DEFAULT X X(2.5) C-\ C-k kills the current process. X X(2.5) BOSS/UW acts as a server for the multi-window Macintosh terminal Xemulator UW. See topic Windows. X X(3.0) File logging (topic Logging), screen redisplay (topic Redisplay), and Xinter-process paste facility (topic Paste) added. These features are due to XGlenn Everhart. X X(3.1) Added record and playback facilities. XQualifiers: X /record`091=filespec`093 default: boss.record X /playback`091=filespec`093 default: boss.record X /gear= is speedup factor for playback; default 1.0 X /lock ignore keyboard input during playback XThe record file will contain the keystrokes from the physical terminal, Xsee the description of these qualifiers. XAdded `094\`094x to request an exit after all processes have terminated. XAdded /quit_on_idle to perform the same function from the command line. XAdded /log to set the default action to logging when creating a process, X and optionally supply a prefix for the log-filename (def:"BOSS"). XDo not close the logfile when logging is stopped, but at quit time. XUse the process name for the log filename iso a number. X `032 X(4.1) Updated for DEC's PTD pseudo TTY drivers. X X(4.2) Added C-e toggle to allow logfiles to be closed when user wants. X`009Fixed wrong lack of setup of log prefix filename. 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 some terminals (Visual 550s in particular) at 9600 baud may Xhave glitches in it. This is because these terminals need flow control Xenabled to operate at 9600 baud, but BOSS doesn't react quickly enough to Xthe control-s sent by the terminal. The solution is to run at 4800 baud or Xslower or to use the FLOW_CONTROL qualifier to BOSS. X XI have seen various strange bugs occurring when using BOSS. These are all Xassociated with VMS running out of some quota. The symptoms range from BOSS Xhanging while creating a process (because LIB$SPAWN does not return) to XSYS$LIBRARY being mis-translated by LINK. As far as I can tell these Xproblems occur only because of the additional stress multiple running jobs Xputs on a users quota's and not because of BOSS problems per se. The Xculprits is usually BYTLM (8000 is too low, 40000 is OK). However PGFLQUO Xis another quota to check. 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 XI know of one program SMP (an algebra system) that grabs the entire PGFLQUO Xon startup. This obviously interfers with BOSS's other processes. The Xsolution is to use a top-level process to run SMP (see topic Process_types). X XPC file transfer using the XMODEM protocol (e.g., with MACX) doesn't work Xthrough BOSS. Kermit seems to work fine. X XAttempting to attach to the process running BOSS from one of its Xsubprocesses causes a hangage. X XControl-\ is used by the Switcher program on the Macintosh. If you are Xrunning your terminal emulation program under Switcher, you need to check X`096Disable keyboard switching' in the Options menu item in Switcher. XAlternatively you can select a different command character with the XCOMMAND_CHARACTER qualifier. X XWhen you run /PLAYBACK, and there is no auto_stuff_string, the first Xcharacter sent to a newly created process is not echoed to your terminal; if Xlogging is active however, the character will show up in the logfile. X2 Windows `032 XIf you are running the UW multi-window Macintosh terminal emulator or the XMeshugena Term Amiga VT200 series terminal emulator, then you can run BOSS Xwith X X $ BOSS/UW X Xand take advantage of a multi-window environment for communicating with the XVAX. (UW stands for Unix Windows.) X XUp to seven processes can be run. Each process is identified by a single Xdigit 1 thru 7. This digit is used in the process name and in the DCL Xprompt. Each process is associated with its own window, named Window #1, Xetc., although the names can be changed within UW. X XBefore you run BOSS/UW, the UW terminal emulator will be operating in Xsingle-window mode. When you start BOSS/UW, this window will close. X XDON'T run BOSS/UW if you're not using the UW software on the Macintosh or Xone of the UW-speaking terminal emulators on the Amiga! X XYou create a window and associated VAX process by selecting New in the XWindows menu. X XYou can select a window by clicking on it (if a portion of it is visible), Xtyping command-1 thru command-7 (for windows 1 thru 7), or by selecting Open Xin the Windows menu. X XYou can close a window by clicking on its close box or by selecting Close in Xthe Windows menu. The associated VAX process remains running. You can view Xthe output at a later time by selecting the window. X XWhen you log out of a process, the window disappears. X XSelecting Shutdown from the File menu causes BOSS to exit and UW to return Xto single window operation. X XFinally, UW also supports Option as a Meta key and high-level mouse support. XBoth these are useful in Emacs. See subtopic Emacs. X XWARNING: UW is a less capable terminal emulator than VersaTerm. Don't Xexpect too much of it! It does however support multiple windows to Xdifferent processes; the lack of this in VersaTerm is its principle defect. X3 Configuration XRead the MacWrite documentation on UW for more information. X XIn UW you can set both the default Window configuration used when a new Xprocess is created (Configure menu) and the configuration of the active Xwindow (Settings in the Window menu). X XI suggest the following default configuration: X X (a) Serial Port: set Flow control on X (b) Protocol: set to "Original UW protocol" X (c) Keyboard: set "META key" X (d) Window Defaults: set "ANSI" X (d') Set TTY Defaults: set "Mouse Action" to "Clipboard" X XSave this configuration as uw.conf. (Then you don't need to repeat it each Xtime you start up.) X3 UW_availability XUW is available in the area at SUMEX.STANFORD.EDU. It's in XUnix shar format in files UNIX-UW-42-PART%.SHAR (PART1 thru PART8). X XAt a minimum you need the UW terminal emulator and (if you have Emacs Xusers) MACMOUSE.EL. X XAt PPL, the terminal emulator and documentation are in X MAC$:`091NEW`093UNIX-UW-42.HQX X(in BinHex format). MACMOUSE.EL is in the default library area for Emacs, XEMACS_LIBRARY:`091LISP`093. X3 Emacs XIn order to run Gnu Emacs under UW, you need to set you Emacs terminal Xtype to "uw", with e.g., X $ setup emacs uw X XThe option key acts as a Meta-shift. Thus Option-F is the same as ESC F X(i.e., goes forward a word). X XYou should set UW to transmit the location of Mouse clicks to the VAX (in XConfigure TTY under Settings in the Window menu). This gets the mouse Xclick transmitted to the VAX for this window only. To get Emacs to Xunderstand what UW sends, insert X X (global-set-key "\em" 'move-mac-cursor) X (autoload 'move-mac-cursor "macmouse" nil t) X Xinto your Emacs init file (sys$login:.emacs). X XHere's what happens with mouse clicks: X X Up or down mouse button in a window selects that window X X A scroll bar/thumbing area for each window with the following features: X the mode lines are horizontal scroll bars X (running from rightmost column to under leftmost column) X the unused right window bar and the dividing lines between X windows are vertical scroll bars X (running from top of window THRU modeline X for vertical scroll bars: X click at line 1 does previous page X click at last line does next page X click anywhere else "thumbs" to the relative portion of the buffer. X shift-click at line 1 scrolls one line down X shift-click at last line scrolls one line up X shift-click elsewhere moves line to top of window X option-shift-click elsewhere moves line to bottom of window X for horizontal scroll bars: X click at column 1 does scroll right one window width X click at last column does scroll left one window width X click anywhere else moves to that "percent" of the buffer width X shift-click at column 1 scrolls one column right X shift-click at last column scrolls one column left X shift-click elsewhere moves column to right of window X option-shift-click elsewhere moves column to left of window X XThere is also basic positioning and kill-buffer support: X click in a buffer moves dot there and selects that buffer X drag copies the dragged region to the kill buffer X shift-drag deletes the dragged region to the kill buffer X X It is possible to use the scrolling and thumbing area to make the region X larger than a single screen; just click, scroll, release. Make sure X that the last scroll is just a down event; the up must be in the buffer. X The last mouse position is remembered for each different buffer (not X window), and thus you can start a drag in one buffer, select another, X go back to the first buffer, etc. X X option-click yanks from the kill buffer X option-shift-click similarly yanks from a named buffer. X3 Other_features XMost of the capabilities of BOSS in its regular mode are available. XHowever, there are some differences in BOSS/UW X XOnly 7 processes can be run (instead of 8). X XThe processes are named 1 thru 7 not A thru Z. X +-+-+-+-+-+-+-+- END OF PART 2 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 3 -+-+-+-+-+-+-+-+ XBOSS/FLOW_CONTROL is used to be set (independent of what you actually ask Xfor). Note that under UW the use of flow control by the Macintosh Xhardware to prevent data overruns of the Mac's buffers is carried out Xindependently of your attempts to control output with C-s and C-q. In Xparticular, C-s and C-q can be used for their regular functions in Emacs, Xeven though the Macintosh and the VAX are still using flow control. X XBOSS/UW sets the default output flag to p (instead of b). This allows Xoutput from all processes to be sent to their respective windows. This Xdefault be overridden with DEFAULT_OUTPUT_FLAG qualifier. And of course Xyou can use C-\ C-b, etc., to set this flag on a per-process basis. X XBOSS/NOCOMMAND_CHARACTER can be used to indicate that no command character Xis to be used. (Thus all characters you type get seen by your VAX Xprocess.) By default, C-\ is still used as a command character. X XBOSS doesn't print "`091Switch to process 5...`093" messages, since the Xswitching is obvious from the arrangement of windows. Other messages X(e.g., the response to C-\ ? should appear in the active window). X XC-\ 3 will tell BOSS to switch to process 3, but UW won't bring that Xwindow to the front. The same comment applies to process-initiated Xswitches (via the BOSS$SWITCH logical name. You should probably use one Xof the other methods for switching processes (clicking on the window, Xcommand-3, etc.) X XBOSS/PROCESS_DEFAULT=TOP will cause BOSS's processes to be top-level Xprocesses. Thus when you select New in the Windows menu, you will see a XUsername: prompt. X XYou can create processes with C-\ C-n 4 or C-\ C-t 4 (for subprocesses and Xtop-level processes). This allows you to create either type of process, Xwhile selecting New in the Windows menu produces only a process of the Xdefault type (governed by BOSS/PROCESS_DEFAULT). X XBOSS/START=(1,2)/STUFF=Emacs will create processes 1 and 2 and start Emacs Xin process 1. This is just the same as BOSS behavior in its regular mode. X3 Misfeatures XOccasionally BOSS loses track of what UW thinks is the active window. XYour typed input will then be sent to the wrong process. This is Xcorrected by switching to some other window (e.g., by clicking on it) and Xthen switching back to the original window. X XOther than the fact that UW supports multiple windows and more intelligent Xmouse behavior with Emacs, UW is a much worse terminal emulator than XVersaTerm. In particular: X X* It doesn't save what scrolls off the screen. X X* I haven't been able to get EVE or LSE to work reasonably. I presume X there's some way of telling these programs what UW can do (via X TERMTABLE); I just haven't managed to get it to work right. Emacs X works just fine though. X X* Keypad is not supported. X X* Arrow keys don't work. X X* UW implements a Tektronix 4010 emulation, but it's a pretty miserable X affair. X X* Can't print. X X* Can't do file transfers. X XI've only implemented the most basic level of UW service under BOSS. The Xnext level allows windows to be retitled from the VAX, as well as setting Xmany of the other attributes of windows. This will most likely not get Ximplemented. X XThe main reason for implementing the UW features in BOSS was to show that Xthe Macintosh can provide a multi-window enviroment for the VAXes. Now we Xhave to get Lonnie Abelbeck to modify VersaTerm to support the UW Xprotocol... X2 Acknowledgements XBOSS was written by Charles Karney based on the PHOTO program written by XAsbed Bedrossian of USC. It utilizes the Pseudo TTY package of Dale Moore Xof CMU and Kevin Carosso of Network Research Co. File logging, screen Xredisplay, and inter-process paste were added by Glenn Everhart X(EVERHART@ARISIA.dnet.ge.com). Record and playback were added by Henk XDavids (hdavids@mswe.dnet.ms.philips.nl). PTD support was added by Steve XAlpert (sra@idx.com). X XUW, the multi-window Macintosh terminal emulator was written by John D. XBruner of LLNL. The Emacs mouse support was written by Gregory S. Lauer of XBBN. X XBugs, questions, etc. to X Charles Karney X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2662 $ CALL UNPACK BOSS.HLP;97 992677057 $ create/nolog 'f' X/* BOSS interactive job controller. XCopyright (c) 1987, 1988 by Charles Karney. All rights reserved. X XWritten by X Charles Karney X Plasma Physics Laboratory E-mail: Karney@Princeton.EDU X Princeton University Phone: +1 609 243 2607 X Princeton, NJ 08543-0451 FAX: +1 609 243 2662 X XBOSS 3.0 features added by Glenn Everhart (EVERHART@ARISIA.dnet.ge.com). X XBased on the PHOTO program of Asbed Bedrossian (USC, asbed@oberon.usc.edu). X XIt utilizes the Pseudo TTY package of Dale Moore (CMU, XDale.Moore@PS1.CS.CMU.EDU) and Kevin Carosso (Network Research Co., Xkvc@nrc.com, kvc@ymir.bitnet). X XThe UW terminal emulator was written by John Bruner (LLNL, Xjbd@mordor.s1.gov). He also defined the UW protocol. X XDESCRIPTION: X XBOSS lets you create up to 8 processes on a VAX/VMS system. Each process Xis identified by a single letter (A thru Z). At most one of these Xprocesses is `096current'. What you type is sent to that process, and outpu Vt Xfrom that process is sent to your terminal. A process which is not current Xcan run but cannot do output. (Output is saved until you make that process Xcurrent.) You usually switch between processes by typing control-\ Xfollowed by the identifying letter. X XYou can run any program under BOSS. For example, you might X run Emacs or EVE in process E X SET HOST to another machine in process H 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 XAs an experimental addition, BOSS can also be run with the UW multiple- Xwindow terminal emulator for the Macintosh or Meshugena-term on Amiga. XIn this case you interact with the various processes through their own Xwindows. X XINSTALLATION: X XCompile and link with X $ @boss_build XInstall with X $ @boss_install ! 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. (The DECWindows drivers Xin VMS 5.3 work just fine.) X XBOSS can be operated without installing it with privileges (but you will Xstill need the pseudo TTYs installed). If BOSS doesn't have 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 us Ved 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 suppor Vt. X C-k command added to kill current process. XVersion 2.6. September 26, 1988 X Write out stuffed strings one character at a time to prevent part of the X string being lost. (A better solution would be to handle the DATA_OVERRUN X condition properly by waiting for an XON AST.) X Fixed bug where the y/n response to process deletion and exiting was X interpreted as a process switch command if the current process completed X in the meantime. X Add /AUTO_STUFF_STRING XVersion 2.7. November 4, 1988 X Ignore error status 0. X Fix C-k so it doesn't try to kill top-level process. XVersion 2.7b 8/22/1990 Glenn Everhart X Added control-I toggle for buffering. Allows buffering of console X output even from active output so one can switch to another window X and get back the buffered text. Switching processes resets. Will X arrange so that some "scrolled off" text can be saved, though the X buffering is switched off on process switches. Another toggle will X be added to allow buffer display to be a one-shot without losing old X contents. XVersion 2.7c 8/23/90 Glenn Everhart X Add C-L toggle to open or close output to BOSSx.LOG for current X process. Make it apply per process. Shutdown will close the file X where orderly. XVersion 2.7d 8/30/90 Glenn Everhart X Add C-G to grab 1 to 9 lines out of one process' buffer (assuming X data is being buffered) and shove it into the next process where X one starts it, similar to boss_stuff operation. Kludgey but possibly X useful. XVersion 2.8. June 23, 1989 X Set /noescape on terminal running BOSS to avoid "partial escape" error XVersion 2.9. August 1, 1989 X Fix error in C-\ C-h documentation. XVersion 3.0. May 31, 1991 X Merge C. Karney mods for V2.9 into Glenn Everhart version 2.7d+ XVersion 3.1. December 12, 1991 Henk Davids X Source processed by "indent -ncdb -di0 -i4 -nfc1 -br -ce -psl -ip -cli1". X Added poor mans record and playback facilities. X Qualifiers: X /record`091=filespec`093 default: boss.record X /playback`091=filespec`093 default: boss.record X /gear= is speedup factor for playback; default 1.0. X if is "I`091nfinite`093" we will skip delays. X /lock ignore keyboard input during playback X The record file will contain the keystrokes from the physical terminal, X interspersed with delay specifications of the form \, X where is the delay in 100 millisecond units. X Added C-x command to request an exit after all processes have terminated. X Added /quit_on_idle to perform the same function from the command line. X Added /log to set the default action to logging when creating a process, X and optionally supply a prefix for the log-filename (def:"BOSS"). X Do not close the logfile when logging is stopped, but at quit time. X Use the process name for the log filename iso a number. XVersion 4.0 March 6,1992 Steve Alpert (sra@idx.com) X Add PTD hooks (for vms 5.4-3++) (update to 3.0 XVersion 4.1 Merge 4.0 changes into version 3.1 (karney@princeton.edu) XVersion 4.1a GCE 4/1992 - Add ctrol-V to close logfile (or open if not X`009present). This allows small logfiles to be created and used X`009from other processes without exiting BOSS. XVersion 4.2 - Fix some problems with BOSS-STUFF with PTD routines by X`009using the single character kludge-o solution that works with X`009PY/TWdrivers. XVersion 4.2a - 19-MAY-1992, Kenn Humborg (elehumborg@orbsen.ucg.ie) X`009Fix things so that if the call to LIB$GET_VM_PAGE returns with X`009"insufficient virtual memory" we just say so nicely rather than X`009exiting the program and killing _all_ the BOSS processes currently X`009running. XVersion 4.3 - 6/1992, Glenn C. Everhart. Added command mode processing X`009started by `094\+ (plus char after the control char). The mode is X`009to accept ONE command line which will be structured as X`009verb args X`009which will let the verb determine what will be done with the X`009args. The command line is terminated by return. The command X`009processing is intended for setup purposes mainly, as it will X`009not strive to keep ASTs going and may cause some I/O to X`009overrun if there's a lot going on or the user is too slow. X`009However the state machine is getting VERY complex! Initial commands X`009understood are S, which sets switch chars to the string X`009"chars" (no brackets in cmd, mind). These are set at each X`009context switch after stuff_chars. E.g. S`094W where `094W is control-W X`009would cause BOSS to emit control-W every time it switched to X`009this process. G does the same for all processes (Global X`009set). There may be up to 7 characters preloaded in this way. X`009Also understood are commands Pnumber and Anumber. Pnumber limits X`009playback of saved information in `094I`094J mode to "number" characters, X`009forced between 100 and BUFSIZE limits, for the current process. X`009Anumber limits this playback for all processes to number. Note X`009that normal buffered mode output is unaffected by this and will X`009allow dump of the whole saved buffer; this is intended to handle X`009the case where everything is being saved past where it would X`009normally be and limit the amount of that which gets played back X`009at every context change. XVersion 4.3a Bug fix by Jerry Leichter XVersion 4.4 From sra@idx.com X`009These are changes to BOSS.C (any version) to minimize the UW window X`009switching. The P1_IAC, P1_FN_OSELW sequence needs to be given only X`009when the output window changes. These modifications eliminate the X`009excessive I/O. XVersion 4.5 From sra@idx.com X`009When a pseudo-terminal goes away, a LIB$FREE_VM_PAGE should be done X`009to reclaim the virtual space associated with that terminal. If this X`009is not done, the space isn't reused and boss may fail to init X`009subprocesses! XVersion 4.6 From elehumborg@orbsen.ucg.ie X`009Fix bug in call to PTD$CREATE... XVersion 4.7 From raxco!galaxy.dnet!gleeve@uunet.uu.net and sra@idx.com X`009Fix to bug fix in call to PTD$CREATE... XVersion 4.9 Frem elehumborg@orbsen.ucg.ie X 3072 pages were being allocated by each call to LIB$GET_VM_PAGE X (somebody coded number_of_pages*512 - LIB$GET_VM_PAGE takes the X number of _pages_ not _bytes_) X 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-a append to log file? (somewhat obsolete; also conflicts with kermit) X Add support for VT420 terminals, where the display buffer can be larger X than the screen. X Add some minimal 'expect' support in playback mode. Somebody care to X port Don Libes' 'expect' package to VMS? X*/ X X#define VERSION`009`009"4.9" X X/* Define the following for VMS 5.4-3++ pseudo terminals */ X#define USE_PTD 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 TIME X#include DVIDEF X#include PERROR X#include FILE X#include ERRNO X#include LIBDEF X X#include STDIO X#include STDLIB X#include CLIMSGDEF X X/* ----- Constants ----- */ 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`009/* can't exceed 512 for PTD's */ 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`009/* Number of process allowed */ X#define NALPHMAX 26`009/* Number of possible names */ X X#define bad(j) !((j) & 1) X#define check(a) if (bad(st = (a))) \ X `123if (st != 0) LIB$SIGNAL(st);`125 else `123`12 V5 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#define CUTP 6 X X#define BRK$C_DEVICE 1 X#define BRK$C_USER16 47 X X/* X * uw protocol X * X * Copyright 1985,1986 by John D. Bruner. All rights reserved. Permission V 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 P1_IAC 0001`009/* interpret as command */ X#define P1_DIR 0100`009/* command direction: */ X#define P1_DIR_HTOM 0000`009/* from host to Mac */ X#define P1_DIR_MTOH 0100`009/* from Mac to host */ X#define P1_FN 0070`009/* function code: */ X#define P1_FN_NEWW 0000`009/* new window */ X#define P1_FN_KILLW 0010`009/* kill (delete) window */ X#define P1_FN_ISELW 0020`009/* select window for input */ X#define P1_FN_OSELW 0030`009/* select window for output */ X#define P1_FN_META 0050`009/* add meta to next data char */ X#define P1_FN_CTLCH 0060`009/* low 3 bits specify char */ X#define P1_FN_MAINT 0070`009/* maintenance functions */ X#define P1_WINDOW 0007`009/* window number mask */ X#define P1_CC 0007`009/* control character specifier: */ X#define P1_CC_IAC 1`009/* IAC */ X#define P1_CC_XON 2`009/* XON */ X#define P1_CC_XOFF 3`009/* XOFF */ X#define P1_MF 0007`009/* maintenance functions: */ X#define P1_MF_ENTRY 0`009/* beginning execution */ X#define P1_MF_ASKPCL 2`009/* request protocol negotiation */ X#define P1_MF_CANPCL 3`009/* suggest protocol */ X#define P1_MF_SETPCL 4`009/* set current protocol */ X#define P1_MF_EXIT 7`009/* execution terminating */ X#define P1_NWINDOW 7`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 X/* Definitions for record/playback modes */ X/* To start a delay specifier in the record file: */ X#define DELAY_ESC '\\' X/* Less than this many secs, and we will consider keystrokes as consecutive: V */ X#define DELAY_THR 0.3 X/* End definitions for record/playback modes */ X Xstruct CHARBLK `123 X unsigned char class, ttype; X unsigned short pgwid; X unsigned ttchr:24; X unsigned char pglen; X unsigned int xchar; X`125; X Xstruct IOSBBLK `123 X unsigned short stats, tmoff, tmntr, tmsiz; X`125; X Xtypedef struct DVIBLK `123 X unsigned short len, code; X char *buffp; X long *lenp; X long terminate; X`125 DVIBLK; X Xint X py_chn`091NPROCMAX`093, py_mb_chn`091NPROCMAX`093, tt_chn, tt_mb_chn, pi Vd`091NPROCMAX`093, X st, cur, kill_proc, count`091NPROCMAX`093, buflen`091NPROCMAX`093, procn Vo`091NALPHMAX`093, X priv`0912`093, privs`0912`093, def_stuff_len, bufmod`091NPROCMAX`093, bu Vfmod2`091NPROCMAX`093, X logmod`091NPROCMAX`093, cutpas`091NPROCMAX`093, kprc, no_phy_io, no_oper V, brkthru, X ctlchar, init, nproc, nalph, recording, record_fd, playback, playback_fd V, X quit_in_progress = FALSE, keyboard_locked = FALSE, synchr_quit = FALSE, X auto_log = FALSE, log_file_prefix_len; X Xfloat gear = 1.0;`009`009/* for playback */ X Xint logfd`091NPROCMAX`093; X Xstatic char X *clr, *bos, *ceol, *ceoln, *retval, ctlchar_str`0914`093, prompt_begin`0 V9130`093, X prompt_end`09130`093, switch_create, flow_control, delete_char, stuff_b Vuf`091256`093, X def_stuff_buf`091256`093, buf`091256`093, image`091IMAGELEN`093, finalt Vp`091NPROCMAX`093`091TPDEVLEN`093, py_mb`091NPROCMAX`093`091MBSIZ`093, X tt_mb`091TTMBSIZ`093, buffer`091NPROCMAX`093`091BUFSIZE`093, term_buf`0 V91MAXBUF`093, blocked`091NPROCMAX`093, X mode`091NPROCMAX`093, pmode`091NPROCMAX`093, defmode, defproc, name`091 VNPROCMAX`093, X py_post`091NPROCMAX`093, proc_type`091NPROCMAX`093, enable_hangup`091NP VROCMAX`093, input_state = NORMAL, X oboss_id = 0, super_ac_mode = PSL$C_SUPER, uw = 0, uw_state = UW_NORMAL V, X uw_meta = 0, first_name, last_name, mac_command = 0, record_file`091256 V`093, X playback_file`091256`093, log_file_prefix`09180`093; X/* Add a command buffer for a command mode to let us joggle more stuff w/o X a super complex state machine. Just handle with normal reads/writes and X accept possible lossage of ast speed etc. if we take too long. */ Xstatic char emitchr`091NPROCMAX`093`0918`093; Xint emitlen`091NPROCMAX`093; X/* echlen is length of buffer to dump out in `094I `094J mode */ Xint echlen`091NPROCMAX`093,echnew`091NPROCMAX`093; Xstatic char cmdlin`091128`093; Xstatic char uwLastWin = 0xff;`009/* minimize window switching */ Xstatic unsigned char input_char; Xstatic char X#ifdef USE_PTD X *tpline`091NPROCMAX`093,`009`009/* filled in later */ X *otpline`091NPROCMAX`093; X#else X tpline`091NPROCMAX`093`091LINESZ`093; X#endif X Xextern int close(); Xextern int creat(); Xextern int write(); X Xextern int BOSS_CLD(); X Xstruct CHARBLK tt_chr, tt_sav_chr; Xstruct IOSBBLK tiosb, tiosbmb, piosb`091NPROCMAX`093, miosb`091NPROCMAX`093; X Xstatic short trnlnm_string_len; Xstatic char trnlnm_string`091BUFSIZE + 151`093; X/* Make this string quite long so we can use it for cut/paste */ X/* n.b. cut/paste a bit kludgey at the moment */ X Xstruct ITEM_LST `123 X unsigned short len, code; X char *addr; X short *retlen; X`125 trnlnm_item = `123 X 80, LNM$_STRING, &trnlnm_string, &trnlnm_string_len X`125; X X/*---- timer functions ---*/ X X/* static timer memory */ Xstatic double last_timestamp = 0.0; X Xstatic double Xtime_so_far() X`123 X timeb_t tms; X X ftime(&tms);`009`009/* get time in millisec units */ X /* resolution is 10 msecs */ X return ((((double) tms.time * 1000.0) + (double) tms.millitm) / 1000.0); X`125 X Xvoid Xstartclock() X`123 X last_timestamp = time_so_far(); X`125 X Xdouble Xelapsedtime() X`123 X return (time_so_far() - last_timestamp); X`125 X Xvoid Xmsleep(millisecs)`009`009/* Hibernate n milliseconds */ X int millisecs; X`123 X int i, sleep; X extern int sys$schdwk();`009/* scheduled wake-up */ X extern int sys$hiber();`009/* hibernate */ X extern int sys$canwak(); X extern int lib$mult_delta_time(); X int delta`0912`093 = `123-10000, -1`125;/* delta 1 millisec in quadword V */ X X if (millisecs <= 0) X`009return; X /* convert millisecs value to delta time in system quad time format */ X i = lib$mult_delta_time(&millisecs, delta); X X check(sys$schdwk(0, 0, delta, 0)); X check(sys$hiber());`009`009/* sleep */ X check(sys$canwak(0, 0));`009/* cancel schdwk request */ X return; X`125 X Xquit() X`123`009`009`009`009/* This is done upon exiting, by exit handler */ X int i, j; X char id`0912`093; X X#ifdef USE_PTD X unsigned long blk,adr; X#endif X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_id, id); X X if (uw && !mac_command) X`009uw_fun(P1_FN_MAINT `124 P1_MF_EXIT, 0, 0); X X if (oboss_id != 0) `123`009/* Restore BOSS$ID */ X`009id`0910`093 = oboss_id; X`009j = LIB$SET_LOGICAL(&d_boss_id, &d_id, 0, 0, 0); X `125 X for (i = 0; i < nproc; i++) `123 X`009if (name`091i`093) `123 X#ifndef USE_PTD X`009 j = SYS$DELMBX(py_mb_chn`091i`093); X`009 if (bad(j)) X`009 printf("`091SYS$DELMBX pseudo-mbx deletion failed`093\n"); X#else X`009 j = PTD$DELETE(py_chn`091i`093); X`009 if (bad(j)) X`009 printf("`091PTD$DELETE pseudo-terminal deletion failed`093\n"); X#endif X`009 /* Last chance close all log files */ X`009 if (logfd`091i`093 != 0) X`009`009j = close(logfd`091i`093); X`009`125 X `125 X quit_in_progress = TRUE; X j = SYS$CANCEL(tt_chn);`009/* Cancel outstanding input request physical X`009`009`009`009 * terminal */ X j = SYS$QIOW(0, tt_chn, IO$_SETMODE, 0, 0, 0, &tt_sav_chr, TTCHRLEN, 0, V 0, 0, 0); X if (bad(j)) X`009printf("`091SYS$QIO /setmode/ failed`093\n"); X if (recording) `123 X`009j = close(record_fd); X `125 X printf("\nEnd BOSS\n"); X`125 X X#ifndef USE_PTD Xmb_srv(n)`009`009`009/* AST for mailbox message on top-level */ X`009`009`009`009/* process completion */ X int n; X`123 X if (proc_type`091n`093 == TOP) `123 X`009if (enable_hangup`091n`093) X`009 comp_srv(n); X`009else `123 X`009 enable_hangup`091n`093 = 1; X`009 check(SYS$QIO(0, py_mb_chn`091n`093, IO$_READVBLK, &miosb`091n`093, V &mb_srv, n, X`009`009`009 &py_mb`091n`093, MBSIZ, 0, 0, 0, 0)); X`009`125 X `125 X`125 X#endif X X/* get termination notice from PTD if in PTD mode */ Xcomp_srv(n)`009`009`009/* AST for completion of processes */ X int n; X`123 +-+-+-+-+-+-+-+- END OF PART 3 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 4 -+-+-+-+-+-+-+-+ X int j; X X#ifdef USE_PTD X unsigned long blk,adr; X/* free virtual memory */ X blk = 4;`009`009/* 2 plus 2 guard pages */ X adr = tpline`091n`093-516;`009/* original inadr`0910`093 */ X j = LIB$FREE_VM_PAGE(&blk,&adr); X if( bad(j)) X printf("`091LIB$FREE_VM_PAGE failed\n"); X#else X j = SYS$DELMBX(py_mb_chn`091n`093); X if( bad(j)) X printf("`091SYS$DELMBX failed\n"); X#endif X if (name`091n`093) X`009procno`091name`091n`093 - first_name`093 = -1; X name`091n`093 = '\0'; X if (uw && !mac_command) X`009uw_fun(P1_FN_KILLW `124 ((n + 1) & P1_WINDOW), 0, 0); X if (kill_proc == n) X`009kill_proc = -1; X if (logfd`091n`093 != 0) X`009j = close(logfd`091n`093); X if (cur == n) X`009cur = -1; X if (synchr_quit && !count_processes()) `123 X`009/* No more processes, and synchr quit requested: exit */ X`009exit(SS$_NORMAL); X `125 X`125 X X/* X Output routines for pseudo terminal X*/ X/* Note: as coded, these routines try to use the XON-AST mechanism to X`009 prevent overflowing the PY with data in playback mode. X`009 However, although the basic mechanism seems to work on the X`009 PY side: X`009 `009start output X`009 `009hibernate X`009`009in the IO AST, check the status: X`009`009`009success, then wake X`009`009`009data overrun, then schedule XON AST X`009`009in the XON AST, restart output if needed X`009`009else wake. X`009we still will get data overrun errors, but now in the read X`009from TW in the subprocess. X`009What am I doing wrong here? X*/ X X/* Request codes */ X#define SET_XON_AST`0091 X#define SET_XOFF_AST`0092 X#define SET_LINE_AST`0093 X X/* Static buffers */ X/* Since only one PY is used at any time for output, we only need 1 copy */ Xstatic unsigned char py_out_buf`09180`093; /* only 1 char used currently */ Xstatic unsigned char *py_out_buf_ptr; Xstatic int py_out_len = 0; Xstatic struct IOSBBLK py_out_iosb; X X/* X AST for py XON notifcation X*/ Xvoid Xpy_out_xon() X`123 X void py_out_srv(); X if (py_out_len) `123 X`009check(SYS$QIO(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, X`009`009 py_out_srv, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X `125 else `123 X`009check(sys$wake(0, 0)); X `125 X`125 X X/* X AST for py output completion X*/ Xvoid Xpy_out_srv() X`123 X if (py_out_iosb.stats != SS$_DATAOVERUN) `123 X`009check(py_out_iosb.stats); X`009py_out_len = 0; X`009check(sys$wake(0, 0)); X `125 else `123 X`009/* update output len and ptr */ X`009py_out_len -= py_out_iosb.tmoff; X`009py_out_buf_ptr += py_out_iosb.tmoff; X`009/* schedule an XON AST */ X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_SETMODE, 0, X`009`009 py_out_xon, 0, 0, 0, 0, SET_XON_AST, 0, 0)); X `125 X`125 X X/* X Send data to current pseudo terminal. X If we are not on_AST_level let's try to be careful not to overflow X the pseudo terminal. X Otherwise, just use the old method (QIOW) for now. X*/ Xvoid Xto_pty(on_AST_level, character) X int on_AST_level; X unsigned char character; X`123 X py_out_len = 1; X py_out_buf_ptr = &py_out_buf`0910`093; X *py_out_buf_ptr = character; X if (on_AST_level) `123 X#ifndef USE_PTD X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, 0, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X`009if (py_out_iosb.stats != SS$_DATAOVERUN) X`009 check(py_out_iosb.stats); X#else X`009otpline`091cur`093`0910`093 = character; X/* should buffer this! */ X`009check(PTD$WRITE(py_chn`091cur`093, 0, 0, otpline`091cur`093-4, py_out_le Vn, 0, 0)); X#endif X `125 else `123 X`009py_out_iosb.tmoff = 0; X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091cur`093, IO$_WRITEVBLK, &py_out_iosb, X`009`009 py_out_srv, 0, X`009`009 py_out_buf_ptr, py_out_len, 0, 0, 0, 0)); X#else X`009otpline`091cur`093`0910`093 = character; X`009check(PTD$WRITE(py_chn`091cur`093, py_out_srv, 0, otpline`091cur`093-4, V py_out_len, 0, 0)); X#endif X`009check(sys$hiber()); X `125 X`125 X Xint Xlow_lib_spawn(n, pty_io, pid, name) X /* Spawns subprocess to speak to pseudo terminal */ X char *pty_io, name; X int n, *pid; X`123 X int flg = 1, len, val, i; X char proc`09120`093, prompt`09150`093, id`0912`093; X $DESCRIPTOR(d_pty_io, pty_io);`009/* PTY name + number */ X $DESCRIPTOR(d_proc, proc);`009`009/* Process name */ X $DESCRIPTOR(d_prompt, prompt);`009/* Prompt */ X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_id, id);`009/* The id */ X d_pty_io.dsc$w_length = strlen(pty_io); X strcpy(proc, getenv("TT")); X len = strlen(proc); X if (proc`091len - 1`093 == ':') X`009proc`091--len`093 = '\0'; X strcat(proc, "_A"); X len = strlen(proc); X proc`091len - 1`093 = name; X d_proc.dsc$w_length = len; X if (proc`0910`093 == '_') `123 X`009d_proc.dsc$w_length--; X`009d_proc.dsc$a_pointer++; X `125 X sprintf(prompt, "%s%c%s", prompt_begin, name, prompt_end); X d_prompt.dsc$w_length = strlen(prompt); X id`0910`093 = 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`009`009 &comp_srv, n, &d_prompt, 0); X if (!bad(val)) X#ifndef USE_PTD X for (i = 0; i < def_stuff_len; i++) `123 X`009check(SYS$QIOW(0, py_chn`091n`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 def_stuff_buf + i, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X `123 X for (i = 0; i < def_stuff_len; i++) `123 X`009otpline`091n`093`0910`093 = def_stuff_buf`091i`093; X/*`009strncpy(otpline`091n`093, def_stuff_buf, def_stuff_len); */ X`009PTD$WRITE(py_chn`091n`093, 0, 0, otpline`091n`093 - 4, 1, 0, 0); X/* check for completion! */ X `125 X `125 X#endif X check(LIB$DELETE_LOGICAL(&d_boss_id, 0)); X return (val); X`125 X Xpy_srv(n)`009`009`009/* AST reads on pseudo terminal */ X int n; X`123 X int j, kkkk; X char *tpptr; X py_post`091n`093 = 0; X#ifndef USE_PTD X check(piosb`091n`093.stats);`009/* Check status */ X count`091n`093 = piosb`091n`093.tmoff + piosb`091n`093.tmsiz; /* How muc Vh was read */ X#else X check(*(short*)(tpline`091n`093-4));`009/* status block! */ X count`091n`093 = *(short*)(tpline`091n`093-2); X#endif X X if (n >= 0 && logmod`091n`093 != 0) `123 X`009if (logfd`091n`093 != 0) `123 X`009 tpptr = tpline`091n`093; X`009 /* write text to active logfile if one exists */ X`009 j = write(logfd`091n`093, tpptr, count`091n`093); X`009`125 X `125 X if (n == cur `124`124 mode`091n`093 == 'p') `123 X`009if (bufmod`091n`093 != 0) `123`009/* Switch buffering separately */ X`009 if (count`091n`093 + buflen`091n`093 < BUFSIZE) `123 X`009`009for (j = 0; j < count`091n`093; j++) X`009`009 buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j` V093; X`009 `125 else `123 X`009`009/* copy buffer down and add in new text */ X`009`009/* First copy text down enough to hold the new line */ X`009`009kkkk = buflen`091n`093 - count`091n`093; X`009`009if (kkkk <= 0) X`009`009 kkkk = 1; X`009`009for (j = 0; j < kkkk; j++) X`009`009 buffer`091n`093`091j`093 = buffer`091n`093`091j + count`091n`093 V`093; X`009`009buflen`091n`093 = buflen`091n`093 - count`091n`093; X`009`009/* Now add the new text after the line */ X`009`009for (j = 0; j < count`091n`093; j++) X`009`009 buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j` V093; X`009 `125 X`009`125`009`009`009/* bufmod */ X`009term_out(n);`009`009/* Write the stuff to the terminal */ X `125 else if (mode`091n`093 == 'w') `123 X`009blocked`091n`093 = 1; X `125 else if (mode`091n`093 == 'o') `123 X`009blocked`091n`093 = 1; X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4, LINESZ V-4)); X#endif X`009py_post`091n`093 = 1; X `125 else if (mode`091n`093 == 'b') `123 X`009if (count`091n`093 + buflen`091n`093 < BUFSIZE) `123 X`009 for (j = 0; j < count`091n`093; j++) X`009`009buffer`091n`093`091buflen`091n`093++`093 = tpline`091n`093`091j`093; X#ifndef USE_PTD X`009 check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py V_srv, n, X`009`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009 check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LI VNESZ-4)); X#endif X`009 py_post`091n`093 = 1; X`009 blocked`091n`093 = 0; X`009`125 else `123 X`009 py_post`091n`093 = 0; X`009 blocked`091n`093 = 1; X`009`125 X `125 X`125 X Xto_term(buf, len, chan) X char *buf; X int len, chan; X`123 X int i, j; X char ochar; X X if (!uw) `123 X`009j = 0; X`009while (j < len) `123 X`009 check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009 `009`009 0, 0, &buf`091j`093, X`009`009`009 (len - j < MAXBUF) ? len - j : MAXBUF, X`009`009`009 0, 0, 0, 0)); X`009 j += MAXBUF; X`009`125 X `125 else if (chan >= 0) `123 X`009j = 0; X`009i = 0; X`009if( chan != uwLastWin ) `123 /* changed windows? */ X`009 term_buf`091i++`093 = P1_IAC; X`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_OSELW `124 ((chan + 1) & V P1_WINDOW); X`009 uwLastWin = chan; X`009`125 X`009while (j < len) `123 X`009 ochar = buf`091j++`093; X`009 if (ochar & 0200) `123 X`009`009term_buf`091i++`093 = P1_IAC; X`009`009term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_META; X`009`009ochar = ochar & 0177; X`009 `125 X`009 switch (ochar) `123 X`009`009case P1_IAC: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_IA VC; X`009`009 break; X`009`009case XON: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_XO VN; X`009`009 break; X`009`009case XOFF: X`009`009 term_buf`091i++`093 = P1_IAC; X`009`009 term_buf`091i++`093 = P1_DIR_HTOM `124 P1_FN_CTLCH `124 P1_CC_XO VFF; X`009`009 break; X`009`009default: X`009`009 term_buf`091i++`093 = ochar; X`009`009 break; X`009 `125 X`009 if (i > MAXBUF - 4) `123`009/* If no room for another meta-xon */ X`009`009check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009`009`009 0, 0, term_buf, i, 0, 0, 0, 0)); X`009`009i = 0;`009`009/* Leave OSELW command in first 2 bytes */ X`009 `125 X`009`125 X`009if (i) `123`009`009/* Spit out rest of buffer */ X`009 check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, X`009 `009`009 0, 0, term_buf, i, 0, 0, 0, 0)); X`009 i = 0; X`009`125 X `125 X`125 X Xterm_out(n) X int n; X`123 X int j, k, kk, kkk, kkkk; X char nname; X char *tpptr; X $DESCRIPTOR(d_boss_switch, "BOSS$SWITCH"); X $DESCRIPTOR(d_boss_stuff, "BOSS$STUFF"); X $DESCRIPTOR(d_lnm_job, "LNM$JOB"); X tpptr = tpline`091n`093; X X if (buflen`091n`093 > 0) `123 X`009/* If buffering current stuff and in a print mode, print only new X`009 * stuff. Thus only print it all if bufmod == 0. */ X`009if (bufmod`091n`093 == 0) `123 X/* Where this process is not in `094i`094j mode and it was buffering data, X echnew will come in as 0, so dump the whole buffer. Limit the size X of what we dump however if we've been keeping history of the buffer X using `094i`094j mode. In that case the echlen number is the number of X chars we dump. */ X`009 if (echnew`091n`093 != 1)`123 X`009 to_term(buffer`091n`093, buflen`091n`093, n); X`009 `125 X`009 if (echnew`091n`093 == 1)`123 X/* send only last 'echlen' bytes to terminal if not in full-buffer mode */ X/* If buflen`091n`093 < echlen`091n`093, normal send. */ X`009 if (buflen`091n`093 <= echlen`091n`093)`123 X`009 to_term(buffer`091n`093, buflen`091n`093, n); X`009 `125 X`009 if (buflen`091n`093 > echlen`091n`093)`123 X`009 to_term(buffer`091n`093+buflen`091n`093-echlen`091n`093, echlen` V091n`093, n); X`009 `125 X`009 echnew`091n`093 = 0; X`009 `125 X`009 if (bufmod2`091n`093 == 0) X`009`009buflen`091n`093 = 0; X`009 else X`009`009bufmod`091n`093 = 1; X`009`125 else /* emit the buffer we currently have to terminal */ X`009 to_term(tpptr, count`091n`093, n); X`009if (blocked`091n`093) X`009 to_term(tpptr, count`091n`093, n); X `125 else X`009to_term(tpptr, count`091n`093, n); X X /* Process boss_switch and boss_stuff logicals if present */ X X j = SYS$TRNLNM(0, &d_lnm_job, &d_boss_switch, &super_ac_mode, &trnlnm_it Vem); X if (!bad(j) && trnlnm_string_len == 1) `123 X`009j = LIB$DELETE_LOGICAL(&d_boss_switch, &d_lnm_job); X`009nname = toupper(trnlnm_string`0910`093); X`009j = SYS$TRNLNM(0, &d_lnm_job, &d_boss_stuff, &super_ac_mode, &trnlnm_ite Vm); X`009if (!bad(j)) `123 X`009 j = LIB$DELETE_LOGICAL(&d_boss_stuff, &d_lnm_job); X`009 trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`125 else `123 X`009 trnlnm_string`0910`093 = '\0'; X`009`125 X`009if (nname >= first_name && nname <= last_name) `123 X`009 mode`091n`093 = 'w'; X`009 mov_to(nname, 0, trnlnm_string, defproc); X`009`125 X `125 X if (py_post`091n`093 == 0) `123 X#ifndef USE_PTD X`009check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 tpline`091n`093, LINESZ, 0, 0, 0, 0));`009/* Queue next AST */ X#else X`009check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LINESZ V-4)); X#endif X`009py_post`091n`093 = 1; X `125 X blocked`091n`093 = 0; X`125 X Xint Xcount_processes() X`123 X int j, i = 0; X X for (j = 0; j < nproc; j++) X`009if (name`091j`093 > 0) X`009 i++; X return (i); X`125 X Xdiag() X`123 X char bufa`0918`093; X int j; X X if (count_processes()) `123 X`009sprintf(buf, "%s`091Processes:", bos); X`009for (j = 0; j < nproc; j++) `123 X`009 if (name`091j`093 > 0) `123 X`009`009if (j == cur) X`009`009 sprintf(bufa, " %c%c*", name`091j`093, mode`091j`093); X`009`009else if (blocked`091j`093) X`009`009 sprintf(bufa, " %c%c+", name`091j`093, mode`091j`093); X`009`009else if (buflen`091j`093 > 0) X`009`009 sprintf(bufa, " %c%c-", name`091j`093, mode`091j`093); X`009`009else X`009`009 sprintf(bufa, " %c%c", name`091j`093, mode`091j`093); X`009`009strcat(buf, bufa); X`009 `125 X`009`125 X`009strcat(buf, "`093 "); X`009strcat(buf, ceoln); X `125 else X`009sprintf(buf, "%s`091No processes`093 %s", bos, ceoln); X term_msg(buf); X`125 X Xint Xnext_slot() X`123 X int j = 0; X while ((j < nproc) && name`091j`093) X`009j++; X return (j == nproc) ? -1 : j; X`125 X Xterm_msg(msg) X char *msg; X`123 X to_term(msg, strlen(msg), cur); X`125 X Xchar * Xget_image(pid)`009`009`009/* Get the image name for a process */ X int pid; X`123 X int j, item; X short len; X char *ptr, *ptra; X $DESCRIPTOR(d_image, image); X ptr = ℑ X if (pid == 0) X`009strcpy(image, ""); X else `123 X`009item = JPI$_IMAGNAME; X`009j = LIB$GETJPI(&item, &pid, 0, 0, &d_image, &len); X`009if (bad(j)) X`009 strcpy(image, ""); X`009else `123 X`009 image`091len`093 = '\0'; X`009 if (len == 0) `123 X`009`009item = JPI$_CLINAME; X`009`009j = LIB$GETJPI(&item, &pid, 0, 0, &d_image, &len); X`009`009if (bad(j)) X`009`009 strcpy(image, ""); X`009`009else X`009`009 image`091len`093 = '\0'; X`009 `125 else `123 X`009`009if ((ptr = strrchr(image, '`093'))) X`009`009 ptr++; X`009`009else X`009`009 ptr = ℑ X`009`009if (ptra = strchr(ptr, '.')) X`009`009 *ptra = '\0'; X`009 `125 X`009`125 X `125 X return (ptr); X`125 X Xint Xmov_to(nname, clear, string, proc_mode)`009/* Switch to process */ X char nname, *string;`009`009/* string is stuffed into input */ X int clear, proc_mode; /* proc_mode says whether to create V process */ X`123 X int ncur, len, i, j; X char *prefix; X prefix = clear ? clr : bos; X len = strlen(string); X if ((cur >= 0) && (name`091cur`093 == nname)) `123`009/* Redundant move V */ X`009bufmod`091cur`093 = 0; X`009mode`091cur`093 = pmode`091cur`093; X`009if (len == 0 & !uw) `123 X`009 sprintf(buf, "%s`091Already in process %c%c, %s`093%s", X`009`009 prefix, nname, mode`091cur`093, get_image(pid`091cur`093), ceoln V); X`009 term_msg(buf); X`009`125 X`009j = 1; X `125 else if ((ncur = procno`091nname - first_name`093) >= 0) `123`009/* V Existing proc */ X`009cur = ncur; X`009mode`091cur`093 = pmode`091cur`093; X`009echnew`091cur`093 = 0; X`009if(bufmod`091cur`093 != 0) echnew`091cur`093 = 1; X`009bufmod`091cur`093 = 0; X`009if (!uw) `123 X`009 sprintf(buf, "%s`091Switch to process %c%c, %s`093%s", X`009`009 prefix, name`091cur`093, mode`091cur`093, get_image(pid`091cur`093 V), ceoln); X`009 term_msg(buf); X`009`125 X`009if (blocked`091cur`093 `124`124 buflen`091cur`093 > 0) X`009 term_out(cur); X`009j = 1; X `125 else if (proc_mode == SWITCH) `123 X`009sprintf(buf, X`009 "%s`091Process %c nonexistent\007 (type %s C-%c %c to create it)`093%s V", X`009`009bos, nname, ctlchar_str, defproc == TOP ? 't' : 'n', X`009`009clear ? nname : tolower(nname), ceoln); X`009term_msg(buf); X`009len = 0; X`009j = 0; X `125 else if ((ncur = (uw ? (nname - first_name) : next_slot())) < 0) `1 V23 X`009if (cur >= 0) X`009 sprintf(buf, "%s`091No process slots left--still in %c%c`093%s", X`009`009 bos, name`091cur`093, mode`091cur`093, ceoln); X`009else X`009 sprintf(buf, "%s`091No process slots left`093%s", bos, ceoln); X`009term_msg(buf); X`009len = 0; X`009j = 0; X `125 else `123 X`009if (!uw) `123 X`009 if (proc_mode == CREATE) X`009`009sprintf(buf, "%s`091Starting subprocess %c...%s", prefix, nname, ceo Vl); X`009 else if (proc_mode == TOP) X`009`009sprintf(buf, "%s`091Starting top-level process %c...%s", prefix, nna Vme, ceol); X`009 term_msg(buf); X`009`125 X`009j = fire_up(ncur, nname, proc_mode); X`009if (bad(j)) `123 X`009 if (!uw) `123 X`009`009if (cur >= 0) X`009`009 sprintf(buf, "failed!!\007--still in %c%c`093%s", X`009`009`009 name`091cur`093, mode`091cur`093, ceoln); X`009`009else X`009`009 sprintf(buf, "failed!!\007`093%s", ceoln); X`009 `125 else `123 X`009`009sprintf(buf, "%s`091Couldn't start start process %c`093%s", X`009`009`009prefix, nname, ceoln); X`009`009uw_fun(P1_FN_KILLW `124 ((ncur + 1) & P1_WINDOW), 0, 0); X`009 `125 X`009 term_msg(buf); X`009 len = 0; X`009`125 else `123 X`009 if (!uw) `123 X`009`009sprintf(buf, "done; now in process %c%c, %s`093%s\r", X`009`009`009nname, mode`091ncur`093, get_image(pid`091ncur`093), ceol); X`009`009term_msg(buf); X`009 `125 X`009 cur = ncur; X`009 if (blocked`091cur`093) X`009`009term_out(cur); X`009`125 X `125 X /* if (j && uw && !mac_command) uw_fun(P1_FN_ISELW `124 ((cur + 1) & X * P1_WINDOW), 0, 0); */ X#ifndef USE_PTD X for (i = 0; i < len; i++) `123 X`009check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 string + i, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X if ( len ) `123 X strncpy(otpline`091ncur`093,string,len); X check(PTD$WRITE(py_chn`091ncur`093, 0, 0, otpline`091ncur`093-4, len, V 0, 0)); X `125 X#endif X/* Handle emitchr string */ X if ((emitchr`091cur`093`0910`093 != '\0') && (emitlen`091cur`093 > 0))`1 V23 X#ifndef USE_PTD X for (i = 0; i < emitlen`091cur`093; i++) `123 X`009 check(SYS$QIOW(0, py_chn`091cur`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 &emitchr`091cur`093`091i`093, 1, 0, 0, 0, 0)); X`009 if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X `125 X#else X if ( emitlen`091ncur`093 ) `123 X strncpy(otpline`091ncur`093,emitchr`091ncur`093,emitlen`091ncur`093); X check(PTD$WRITE(py_chn`091ncur`093, 0, 0, otpline`091ncur`093-4, emit Vlen`091ncur`093, 0, 0)); X `125 X#endif X `125 X/* */ X return (j); X`125 X Xprint_help() X`123 X if (ctlchar >= 0 && ctlchar < 040) X`009sprintf(buf, "%sBOSS commands are preceded by %s (control-%c). \ XThe commands are:%s", bos, ctlchar_str, tolower(ctlchar + 0100), ceoln); X else X`009sprintf(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 immediately%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-x Quit when no more processes active%s", ceoln V); 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) `123 X`009sprintf(buf, "\r %c Clear screen and switch to process %c%s", X`009`009first_name, first_name, ceoln); X`009term_msg(buf); X `125 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 subprocess%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-i Toggle buffering of active output%s", ceoln) V; X term_msg(buf); X sprintf(buf, "\r C-j Toggle multishot buffering%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-l Toggle logging to BOSSn.LOG%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-e Close logfile BOSSn.LOG%s", ceoln); X term_msg(buf); X sprintf(buf, "\r + Enter cmd mode for 1 cmd%s", ceoln); X term_msg(buf); X sprintf(buf, "\r C-g Get n lines of cur proc -> next%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 V", 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`125 X Xvoid Xstart_logging(cur) X int cur; X`123 X char lognam`09180`093; X X logmod`091cur`093 = 1; X if (logfd`091cur`093 == 0) `123 X`009/* no open logfile yet, compose name and open */ X`009strcpy(lognam, log_file_prefix); X`009lognam`091log_file_prefix_len`093 = name`091cur`093; X`009strcpy(&lognam`091log_file_prefix_len + 1`093, ".LOG"); X`009logfd`091cur`093 = creat(lognam, 0, "mbf=3"); X `125 X`125 X X/* X Read on real terminal server X This routine will either be called at AST level for physical terminal X reads (on_AST_level true), or from main level in case of playback (false) V. X*/ X Xtt_srv(on_AST_level) X int on_AST_level; X`123 X int i; X int k, kk, kkk, kkkk; X int n; X char nname, nmode, *desc, dismiss, function, arg; X char lognam`09180`093; X char *lnptr; X X if (quit_in_progress) X`009return;`009`009`009/* ignore AST from sys$cancel */ X X check(tiosb.stats); X X dismiss = 0; X X if (playback && on_AST_level) `123 X`009/* User interrupts a playback session */ X`009if (keyboard_locked) `123 X`009 /* ignoring keyboard */ X`009 dismiss = 1; X`009`125 else `123 X`009 playback = 0; X`009 /* todo: main() may be in a delay sleep - wake up? */ X`009`125 X `125 X /* recording first */ X if (recording && !dismiss) `123 X`009double delay = elapsedtime(); X`009startclock(); X`009if (delay > DELAY_THR) `123 X`009 /* write a delay entry if more than DELAY_THR secs between X`009 * keystrokes */ X`009 delay *= 10.0;`009/* convert to 100 millisecs units */ X`009 sprintf(buf, "%c%d\n", DELAY_ESC, (int) delay); X`009 write(record_fd, buf, strlen(buf)); X`009`125 X`009if (input_char == DELAY_ESC) X`009 write(record_fd, &input_char, 1); X`009write(record_fd, &input_char, 1); X `125 X /* do UW decoding at first */ X if (uw) `123 X`009mac_command = 1; X`009switch (uw_state) `123 X`009 case UW_NORMAL: X`009`009if (input_char == P1_IAC) `123 X`009`009 uw_state = UW_PENDING; X`009`009 dismiss = 1; X`009`009`125 X`009`009break; X`009 case UW_PENDING: X`009`009uw_state = UW_NORMAL; X`009`009dismiss = 1; X`009`009if ((input_char & P1_DIR) == P1_DIR_MTOH) `123 X`009`009 function = input_char & P1_FN; X`009`009 arg = input_char & P1_WINDOW; X`009`009 switch (function) `123 X`009`009`009case P1_FN_NEWW: X`009`009`009 mov_to(first_name + (arg - 1), 0, "", defproc); X`009`009`009 break; X`009`009`009case P1_FN_KILLW: X`009`009`009 if (name`091arg - 1`093 > 0 && proc_type`091arg - 1`093 != T VOP) X`009`009`009`009st = SYS$DELPRC(&pid`091arg - 1`093, 0); X`009`009`009 break; X`009`009`009case P1_FN_ISELW: X`009`009`009 mov_to(first_name + (arg - 1), 0, "", defproc); X`009`009`009 break; X`009`009`009case P1_FN_OSELW:`009/* shouldn't ever occur */ X`009`009`009 break; X`009`009`009case P1_FN_META: X`009`009`009 uw_meta = 1; X`009`009`009 break; X`009`009`009case P1_FN_CTLCH: X`009`009`009 dismiss = 0; X`009`009`009 switch (arg) `123 X`009`009`009`009case P1_CC_IAC: X`009`009`009`009 input_char = P1_IAC; +-+-+-+-+-+-+-+- END OF PART 4 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 5 -+-+-+-+-+-+-+-+ X`009`009`009`009 break; X`009`009`009`009case P1_CC_XON: X`009`009`009`009 input_char = XON; X`009`009`009`009 break; X`009`009`009`009case P1_CC_XOFF: X`009`009`009`009 input_char = XOFF; X`009`009`009`009 break; X`009`009`009`009default: X`009`009`009`009 dismiss = 1; X`009`009`009`009 break; X`009`009`009 `125 X`009`009`009 break; X`009`009`009case P1_FN_MAINT: X`009`009`009 switch (arg) `123 X`009`009`009`009case P1_MF_ENTRY: /* Shouldn't get this */ X`009`009`009`009 break; X`009`009`009`009case P1_MF_ASKPCL: X`009`009`009`009 uw_fun(P1_FN_MAINT `124 P1_MF_CANPCL, 040, 1); X`009`009`009`009 break; X`009`009`009`009case P1_MF_CANPCL: /* Shouldn't get this */ X`009`009`009`009 uw_state = UW_CANPCL; X`009`009`009`009 break; X`009`009`009`009case P1_MF_SETPCL: X`009`009`009`009 uw_state = UW_SETPCL; X`009`009`009`009 break; X`009`009`009`009case P1_MF_EXIT: X`009`009`009`009 exit(SS$_NORMAL); X`009`009`009`009 break; X`009`009`009 `125 X`009`009`009 break; X`009`009`009case UW_CANPCL: X`009`009`009 if (input_char == 040) X`009`009`009`009uw_fun(P1_MF_SETPCL, 040, 1); X`009`009`009 else X`009`009`009`009uw_fun(P1_MF_CANPCL, 040, 1); X`009`009`009 uw_state = UW_NORMAL; X`009`009`009 break; X`009`009`009case UW_SETPCL: X`009`009`009 if (input_char != 040) `123 X`009`009`009`009sprintf(buf, X`009`009`009`009`009"%s`091Don't understand this protocol: %d`093%s", X`009`009`009`009`009bos, input_char, ceoln); X`009`009`009 `125 X`009`009`009 uw_state = UW_NORMAL; X`009`009`009 break; X`009`009 `125 X`009`009`125 X`009`125 X`009if (uw_meta && !dismiss) `123 X`009 uw_meta = 0; X`009 input_char = 0200 `124 input_char; X`009`125 X`009mac_command = 0; X `125 X if (!dismiss) `123 X`009if (input_char == 0177) X`009 input_char = delete_char; X`009else if (input_char == delete_char) X`009 input_char = 0177; X`009if (input_state == NORMAL && cur < 0) X`009 input_state = PENDING; X`009switch (input_state) `123 X`009 case NORMAL: X`009`009if (input_char == ctlchar) X`009`009 input_state = PENDING; X`009`009else `123 X`009`009 to_pty(on_AST_level, input_char); X`009`009`125 X`009`009break; X`009 case PENDING: X`009`009if (input_char == ctlchar) `123 X`009`009 if (cur >= 0) `123 X`009`009`009to_pty(on_AST_level, input_char); X`009`009`009input_state = NORMAL; X`009`009 `125 X`009`009 break; X`009`009`125 X`009`009switch (input_char) `123 X`009`009 case '+':`009/* Plus sign */ X/* Fire up command mode */ X/* Command mode is responsible for its' own prompting, etc. */ X`009`009`009cmdmode(cur); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\016':`009/* C-n */ X`009`009`009input_state = CREATE; X`009`009`009break; X`009`009 case '\024':`009/* C-t */ X`009`009`009input_state = TOP; X`009`009`009break; X`009`009 case '\030':`009/* C-x */ X`009`009`009synchr_quit = TRUE; X`009`009`009sprintf(buf, X`009`009`009`009"%s`091Boss: will exit when processes terminate`093%s", X`009`009`009`009bos, ceoln); X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\032':`009/* C-z */ X`009`009`009if (count_processes()) `123 X`009`009`009 diag(); X`009`009`009 sprintf(buf, X`009`009`009 `009 "`091Do you really want to quit (y or n)?`093%s\007" V, X`009`009`009`009 ceol); X`009`009`009 term_msg(buf); X`009`009`009 input_state = END; X`009`009`009`125 else X`009`009`009 exit(SS$_NORMAL); X`009`009`009break; X`009`009 case '\007':`009/* C-g */ X`009`009`009if (cur < 0) `123 X`009`009`009 term_msg("\007"); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009 "%s`091Enter # lines to move (1-9):%s", bos, ceoln); X`009`009`009 term_msg(buf); X`009`009`009 kprc = cur; X`009`009`009 input_state = CUTP; X`009`009`009`125 X`009`009`009break; X`009`009 case '\013':`009/* C-k */ X`009`009`009if (cur < 0) `123 X`009`009`009 term_msg("\007"); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else if (proc_type`091cur`093 == TOP) `123 X`009`009`009 sprintf(buf, "%s`091Can't kill top-level process %c`093%s\00 V7", X`009`009`009`009 bos, name`091cur`093, ceoln); X`009`009`009 term_msg(buf); X`009`009`009 input_state = NORMAL; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009`009 "%s`091Do you really want to kill process %c (y or n)?`0 V93%s\007", X`009`009`009`009 bos, name`091cur`093, ceol); X`009`009`009 term_msg(buf); X`009`009`009 kill_proc = cur; X`009`009`009 input_state = KILL; X`009`009`009`125 X`009`009`009break; X`009`009 case '\010':`009/* C-h */ X`009`009`009print_help(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '?': X`009`009`009diag(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\002':`009/* C-b */ X`009`009 case '\017':`009/* C-o */ X`009`009 case '\020':`009/* C-p */ X`009`009 case '\027':`009/* C-w */ X`009`009`009if (input_char == '\002') X`009`009`009 desc = "Buffer"; X`009`009`009else if (input_char == '\017') X`009`009`009 desc = "Discard"; X`009`009`009else if (input_char == '\020') X`009`009`009 desc = "Print"; X`009`009`009else if (input_char == '\027') X`009`009`009 desc = "Stop"; X`009`009`009nmode = input_char + 0140; X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output by default`093%s", X`009`009`009`009 bos, desc, ceoln); X`009`009`009`125 else `123 X`009`009`009 mode`091cur`093 = nmode; X`009`009`009 pmode`091cur`093 = nmode; X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output from process %c`093%s", X`009`009`009`009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\011':`009/* C-i */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = bufmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Actv Buffered"; X`009`009`009`009bufmod`091cur`093 = 1; X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Actv Unbuffered"; X`009`009`009`009bufmod`091cur`093 = 0; X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, X`009`009`009 `009 "%s`091%s output from process %c`093%s", X`009`009`009`009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\012':`009/* C-j */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = bufmod2`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Multshot Buffered"; X`009`009`009`009bufmod2`091cur`093 = 1; X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Multshot Unbuffered"; X`009`009`009`009bufmod2`091cur`093 = 0; X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\014':`009/* C-l */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = logmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Logging enabled"; X`009`009`009`009start_logging(cur); X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Logging disabled"; X`009`009`009`009logmod`091cur`093 = 0; X`009`009`009`009/* do not close logfile yet, might get enable X`009`009`009`009 * later */ X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\005':`009/* C-e */ X`009`009`009if (cur >= 0) `123 X`009`009`009 kkk = logmod`091cur`093; X`009`009`009 if (kkk == 0) `123 X`009`009`009`009desc = "Logging enabled"; X`009`009`009`009start_logging(cur); X`009`009`009 `125 X`009`009`009 if (kkk != 0) `123 X`009`009`009`009desc = "Logging disabled"; X`009`009`009`009logmod`091cur`093 = 0; X`009`009`009`009k = close( logfd`091cur`093 ); X`009`009`009`009/* do not close logfile yet, might get enable X`009`009`009`009 * later */ X`009`009`009 `125 X`009`009`009 /* Hack to keep current mode */ X`009`009`009 nmode = 'b'; X`009`009`009`125 X`009`009`009if (cur < 0) `123 X`009`009`009 defmode = nmode; X`009`009`009`125 else `123 X`009`009`009 sprintf(buf, "%s`091%s output from process %c`093%s", X`009`009`009 `009 bos, desc, name`091cur`093, ceoln); X`009`009`009`125 X`009`009`009term_msg(buf); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\177':`009/* C-? */ X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 default: X`009`009`009nname = toupper(input_char); X`009`009`009if (nname >= first_name && nname <= last_name) `123 X`009`009`009 /* fill in any "cut/paste" text being brought in X`009`009`009 * from other proc */ X`009`009`009 n = cur; X`009`009`009 /* Zero text string if not being used */ X`009`009`009 trnlnm_string`0910`093 = '\0'; X`009`009`009 if (n >= 0 && cutpas`091n`093 > 0) `123 X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009/* Paste last n lines (up to max in buffer) X`009`009`009`009 * back */ X`009`009`009`009/* We are assured the dest. process number is X`009`009`009`009 * legal here */ X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* Count CR's (newlines) in buffer, then go X`009`009`009`009 * back by n of them and copy from there to X`009`009`009`009 * the end of buffer into the string that X`009`009`009`009 * would be used for boss_stuff work. X`009`009`009`009 * This avoids another mechanism. */ X`009`009`009`009kkk = k - cutpas`091n`093; X`009`009`009`009if (kkk < 0) X`009`009`009`009 kkk = 0; X`009`009`009`009/* reset save amount for next time */ X`009`009`009`009cutpas`091n`093 = 0; X`009`009`009`009kk = buflen`091n`093 + 100; X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009`009if (k == kkk) X`009`009`009`009`009 kk = kkkk; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* kk is now index into start of cut/paste X`009`009`009`009 * area, buflen`091n`093 = end */ X`009`009`009`009/* guard against empty buffer */ X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009if (kk < buflen`091n`093) `123 X`009`009`009`009 for (kkkk = kk; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009`009trnlnm_string`091trnlnm_string_len++`093 = X`009`009`009`009`009 buffer`091n`093`091kkkk`093; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`009`009 `125 X`009`009`009 /* end cut/paste */ X X`009`009`009 mov_to(nname, uw ? 0 : input_char < 'a', X`009`009`009`009 trnlnm_string, X`009`009`009`009 switch_create ? defproc : SWITCH); X`009`009`009`125 else X`009`009`009 term_msg("\007"); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009`125 X`009`009break; X`009 case CREATE: X`009 case TOP: X`009`009switch (input_char) `123 X`009`009 case '\016':`009/* C-n */ X`009`009`009input_state = CREATE; X`009`009`009break; X`009`009 case '\024':`009/* C-t */ X`009`009`009input_state = TOP; X`009`009`009break; X`009`009 case '\010':`009/* C-h */ X`009`009`009print_help(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '?': X`009`009`009diag(); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 case '\177':`009/* C-? */ X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009 default: X`009`009`009nname = toupper(input_char); X`009`009`009if (nname >= first_name && nname <= last_name) `123 X`009`009`009 /* fill in any "cut/paste" text being brought in X`009`009`009 * from other proc */ X`009`009`009 n = cur; X`009`009`009 /* Zero text string if not being used */ X`009`009`009 trnlnm_string`0910`093 = '\0'; X`009`009`009 if (n >= 0 && cutpas`091n`093 > 0) `123 X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009/* Paste last n lines (up to max in buffer) X`009`009`009`009 * back. We are assured the dest. process X`009`009`009`009 * number is legal here */ X`009`009`009`009k = 0; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* Count LF's (newlines) in buffer, then go X`009`009`009`009 * back by n of them and copy from there to X`009`009`009`009 * the end of buffer into the string that X`009`009`009`009 * would be used for boss_stuff work. X`009`009`009`009 * This avoids another mechanism. */ X`009`009`009`009kkk = k - cutpas`091n`093; X`009`009`009`009if (kkk < 0) X`009`009`009`009 kkk = 0; X`009`009`009`009/* reset save amount for next time */ X`009`009`009`009cutpas`091n`093 = 0; X`009`009`009`009k = 0; X`009`009`009`009kk = buflen`091n`093 + 100; X`009`009`009`009for (kkkk = 0; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009 if (buffer`091n`093`091kkkk`093 == '\n') `123 X`009`009`009`009`009k++; X`009`009`009`009`009if (k == kkk) X`009`009`009`009`009 kk = kkkk; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009/* kk is now index into start of cut/paste X`009`009`009`009 * area, buflen`091n`093 = end */ X`009`009`009`009/* guard against empty buffer */ X`009`009`009`009trnlnm_string_len = 0; X`009`009`009`009if (kk < buflen`091n`093) `123 X`009`009`009`009 for (kkkk = kk; kkkk < buflen`091n`093; kkkk++) `123 X`009`009`009`009`009trnlnm_string`091trnlnm_string_len++`093 = X`009`009`009`009`009 buffer`091n`093`091kkkk`093; X`009`009`009`009 `125 X`009`009`009`009`125 X`009`009`009`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X`009`009`009 `125 X`009`009`009 /* end cut/paste */ X`009`009`009 mov_to(nname, uw ? 0 : input_char < 'a', X`009`009`009`009 trnlnm_string, input_state); X`009`009`009`125 else X`009`009`009 term_msg("\007"); X`009`009`009input_state = NORMAL; X`009`009`009break; X`009`009`125 X`009`009break; X`009 case END: X`009`009if (toupper(input_char) == 'Y') `123 X`009`009 term_msg(" Yes\r"); X`009`009 exit(SS$_NORMAL); X`009`009`125 else `123 X`009`009 term_msg(" No\r\n"); X`009`009`125 X`009`009input_state = NORMAL; X`009`009break; X`009 case CUTP: X`009`009/* kprc has proc. number to cut from */ X`009`009kkk = input_char; X`009`009/* Make sure char is 1 to 9, else discard and ignore */ X`009`009/* Add small bit to allow multiple digits of count */ X`009`009if (kkk > 48 && kkk < 58) `123 X`009`009 kk = cutpas`091kprc`093 * 10; X`009`009 cutpas`091kprc`093 = kk + kkk - 48; X`009`009 input_state = CUTP; X`009`009`125 else `123 X`009`009 input_state = NORMAL; X`009`009`125 X`009`009break; X`009 case KILL: X`009`009if (toupper(input_char) == 'Y') `123 X`009`009 if (kill_proc >= 0 && name`091kill_proc`093 > 0) `123 X`009`009`009if (proc_type`091kill_proc`093 == TOP) `123 X`009`009`009 sprintf(buf, X`009`009`009 `009"%s`091Can't kill top-level process %c`093%s\007", X`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009`125 else `123 X`009`009`009 st = SYS$DELPRC(&pid`091kill_proc`093, 0); X`009`009`009 if (bad(st)) X`009`009`009`009sprintf(buf, "%s`091Couldn't kill process %c`093%s", X`009`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009 else X`009`009`009`009sprintf(buf, "%s`091Killed process %c`093%s", X`009`009`009`009`009bos, name`091kill_proc`093, ceoln); X`009`009`009`125 X`009`009 `125 else X`009`009`009sprintf(buf, "%s`091Process already killed`093%s", X`009`009`009`009bos, ceoln); X`009`009 term_msg(buf); X`009`009`125 else `123 X`009`009 term_msg(" No\r\n"); X`009`009`125 X`009`009input_state = NORMAL; X`009`009kill_proc = -1; X`009`009break; X`009`125 X `125 X /* re-post read AST on real term */ X /* but only if really on_AST_level */ X if (on_AST_level) `123 X`009check(SYS$QIO(0, tt_chn, IO$_READVBLK, &tiosb, &tt_srv, TRUE, X`009`009 &input_char, 1, 0, 0, 0, 0)); X `125 X`125 X Xuw_fun(code, arg, count) X char code, arg; X int count; X`123 X term_buf`0910`093 = P1_IAC; X term_buf`0911`093 = P1_DIR_HTOM `124 code; X if (count > 0) X`009term_buf`0912`093 = arg; X check(SYS$QIOW(0, tt_chn, IO$_WRITEVBLK, &tiosb, 0, 0, X `009`009 term_buf, 2 + count, 0, 0, 0, 0)); X`125 X X/* cmdmode(cur); */ X/* Handle commands too intricate for normal work. Can use global cmdlin X to read data into. */ Xcmdmode(curprc) X int curprc; X`123 X int j,k,n; X term_msg("\r\nCmd>"); X/* zero the command line initially */ X for (j=0; j < 128; j++)`123 X cmdlin`091j`093 = '\0';`125 X check(SYS$QIOW(4,tt_chn,IO$_READVBLK, &tiosb,0,0,&cmdlin,126,0,0,0,0)); X term_msg(cmdlin); /* echo the line */ X/* got command line in now...go process it and return */ X/* Sstart-chars - set start chars in current process; ctrl-W a good choice * V/ X if (toupper(cmdlin`0910`093) == 'S')`123 X/* start charstring is rest of line */ X if(curprc >= 0)`123 X emitlen`091curprc`093 = 0; X for (j = 0; j <= 7 ; j++)`123 emitchr`091curprc`093`091j`093 = '\0';`1 V25 X for (j = 1; j < 7; j++)`123 X if (cmdlin`091j`093 == '\0')break; X if (cmdlin`091j`093 == '\r')break; X emitchr`091curprc`093`091j-1`093 = cmdlin`091j`093; X emitlen`091curprc`093++; X `125 X `125 X `125 X/* Gstart-chars - set start chars for all processes */ X if (toupper(cmdlin`0910`093) == 'G')`123 X/* start charstring is rest of line */ X for (k=0;k < NPROCMAX; k++)`123 X for (j = 0; j <= 7 ; j++)`123 emitchr`091k`093`091j`093 = '\0';`125 X emitlen`091k`093 = 0; X for (j = 1; j < 7; j++)`123 X if (cmdlin`091j`093 == '\0')break; X if (cmdlin`091j`093 == '\r')break; X emitchr`091k`093`091j-1`093 = cmdlin`091j`093; X emitlen`091k`093++; X `125 X `125 X `125 X/* Pnumber plays back only "number" chars for the buffer, not X the entire buffer size. "Number" must be between 100 and X BUFSIZE, the 100 chosen to allow current output by. */ X if(toupper(cmdlin`0910`093) == 'P')`123 X sscanf(&cmdlin`0911`093,"%d",&n); X`009printf("`091Setting save print to (%d)\n", X`009 n); X if(curprc >= 0)`123 X if ((n >= 100) && ( n <= BUFSIZE))`123 X k = n; X `125else`123 X k = BUFSIZE;`125 X echlen`091curprc`093 = k; X `125 X `125 X/* Anumber plays back only "number" chars for the buffer, not X the entire buffer size. "Number" must be between 100 and X BUFSIZE, the 100 chosen to allow current output by. */ X/* Unlike Pnumber, Anumber operates on all processes. */ X if(toupper(cmdlin`0910`093) == 'A')`123 X sscanf(&cmdlin`0911`093,"%d",&n); X`009printf("`091Setting save prints to (%d)\n", X`009 n); X for (j=0; j < NPROCMAX ; j++)`123 X if ((n >= 100) && ( n <= BUFSIZE))`123 X k = n; X `125else`123 X k = BUFSIZE;`125 X echlen`091j`093 = k; X `125 X `125 X`125 X Xget_tt_info() X`123 X $DESCRIPTOR(d_tt, "SYS$COMMAND"); X /* Get a channel & mailbox of terminal */ X check(LIB$ASN_WTH_MBX(&d_tt, &TTMBSIZ, &TTMAXSIZ, &tt_chn, &tt_mb_chn)); X /* Get the terminal characteristics. */ X check(SYS$QIOW(0, tt_chn, IO$_SENSEMODE, 0, 0, 0, X `009`009 &tt_chr, TTCHRLEN, 0, 0, 0, 0)); X tt_sav_chr = tt_chr; X tt_chr.ttchr `124= TT$M_NOECHO;/* term will be Noecho */ X tt_chr.ttchr &= `126TT$M_ESCAPE;`009/* no escape */ X tt_chr.ttchr &= `126TT$M_HOSTSYNC;`009/* no host sync */ X if (flow_control) X`009tt_chr.ttchr `124= TT$M_TTSYNC;`009/* do sync at BOSS level */ X else X`009tt_chr.ttchr &= `126TT$M_TTSYNC;`009/* do sync at subprocess level */ X tt_chr.xchar `124= TT2$M_PASTHRU;`009/* it will be PASTRHU */ X if (brkthru) `123 X`009tt_chr.ttchr `124= TT$M_MBXDSABL;`009/* no hangup messages */ X`009tt_chr.ttchr `124= TT$M_NOBRDCST;`009/* disable direct broadcast */ X`009tt_chr.xchar `124= TT2$M_BRDCSTMBX;`009/* send them to mailbox X`009`009`009`009`009`009 * instead */ X `125 X check(SYS$QIOW(0, tt_chn, IO$_SETMODE, 0, 0, 0, X `009`009 &tt_chr, TTCHRLEN, 0, 0, 0, 0)); X`125 X Xfix_a_tp(n)`009`009`009/* Set up a Pseudo term */ X int n; X`123 X int dev_depend, tp_chn, blk, status; X struct CHARBLK tw_chr; X struct IOSBBLK iosb; X#ifndef USE_PTD X struct DVIBLK dvi_stuff = `1234, DVI$_DEVDEPEND, &dev_depend, 0, 0`125; X#else X struct DVIBLK dvi_stuff = `1234, DVI$_UNIT, &dev_depend, 0, 0`125; X long inadr`0912`093;`009`009/* for LIB$GET_VM_PAGE */ X#endif X X#ifndef USE_PTD X $DESCRIPTOR(d_pynam, "PYA0:");`009/* Template. */ X $DESCRIPTOR(d_finaltp, &finaltp`091n`093); X /* Assign a mailbox to PYA */ X check(LIB$ASN_WTH_MBX(&d_pynam, &MBSIZ, &MAXSIZ, &py_chn`091n`093, X `009`009`009 &py_mb_chn`091n`093)); X /* Use $GETDVI to get the device dependent characteristics, which X * contains the associated terminal device's unit number. */ X check(SYS$GETDVI(0, py_chn`091n`093, 0, &dvi_stuff, &iosb, 0, 0, 0)); X check(iosb.stats); X#endif X X tw_chr = tt_sav_chr; X tw_chr.xchar `124= TT2$M_HANGUP; X X#ifndef USE_PTD X sprintf(finaltp`091n`093, "TWA%d:", dev_depend); X d_finaltp.dsc$w_length = strlen(&finaltp`091n`093); X /* Get a channel on this TWA */ X if (bad(SYS$ASSIGN(&d_finaltp, &tp_chn, 0, 0))) `123 X`009sprintf(&finaltp`091n`093, "TPA%d:", dev_depend);`009/* TWA doesn't work V; X`009`009`009`009`009`009`009 * try TPA */ X`009d_finaltp.dsc$w_length = strlen(&finaltp`091n`093); X`009check(SYS$ASSIGN(&d_finaltp, &tp_chn, 0, 0)); X `125 X if (no_phy_io) X`009check(SYS$SETPRV(1, &priv, 0, 0)); X /* Make it look like a terminal */ X if (bad(SYS$QIOW(0, tp_chn, IO$_SETCHAR, 0, 0, 0,`009/* This needs PHY_I VO X`009`009`009`009`009`009`009 * priv */ X`009`009 &tw_chr, TTCHRLEN, 0, 0, 0, 0))) X`009check(SYS$QIOW(0, tp_chn, IO$_SETMODE, 0, 0, 0, X`009`009 &tw_chr, TTCHRLEN, 0, 0, 0, 0)); X if (no_phy_io) X`009check(SYS$SETPRV(0, &priv, 0, 0)); X check(SYS$DASSGN(tp_chn));`009/* We don't need it. only the mailbox */ X /* in fact keeping it kills us. */ X#else X blk = 4;`009`009/* 2 plus 2 guard pages */ X status = LIB$GET_VM_PAGE(&blk,&inadr`0910`093); X if (status == LIB$_INSVIRMEM) `123`009/* If we can't get the memory, just V */ X sprintf(buf,"No memory left!!..."); /* say so rather than crashing out * V/ X term_msg(buf);`009`009`009/* killing all the processes. */ X return (status); X `125 X check(status); X tpline`091n`093 = (char *)((inadr`0910`093 += 512) +4);`009/* where data g Voes */ X inadr`0911`093 = inadr`0910`093 + 6 * 512; X otpline`091n`093 = tpline`091n`093 + 3 * 512;`009`009/* split the differen Vce? */ X X/* comp_srv will get notify if ptd exits via spawn */ X if (proc_type`091n`093 == TOP) `123 X check(PTD$CREATE(&tp_chn,0,&tw_chr,TTCHRLEN,&comp_srv,n,0,&inadr`0910` V093)); X `125 else `123 X check(PTD$CREATE(&tp_chn,0,&tw_chr,TTCHRLEN,0,0,0,&inadr`0910`093)); X `125 X py_chn`091n`093 = tp_chn; X/* X * Use $GETDVI to get the device dependent characteristics, which X * contains the associated terminal device's unit number. X */ X check(SYS$GETDVI(0,py_chn`091n`093,0,&dvi_stuff,&iosb,0,0,0)); X check(iosb.stats); X sprintf(finaltp`091n`093,"FTA%d:",dev_depend); X#endif X return (1); X`125 X Xbroadcast_handler() X`123`009`009`009`009/* handle broadcasts to BOSS */ X int j, len; X X $DESCRIPTOR(d_tt_mb, tt_mb); X $DESCRIPTOR(d_finaltp, finaltp`091cur`093); X X check(tiosbmb.stats);`009/* Check status */ X len = ((0377 & tt_mb`09121`093) << 8) + (0377 & tt_mb`09120`093); /* mes Vsage length */ X if (cur < 0) `123 X`009term_msg("\r\n"); X`009to_term(&(tt_mb`09122`093), len, 1); X`009term_msg("\r"); X `125 else `123 X`009d_tt_mb.dsc$w_length = len; X`009d_tt_mb.dsc$a_pointer = &(tt_mb`09122`093); X`009if (no_oper) X`009 check(SYS$SETPRV(1, &privs, 0, 0)); X`009check(SYS$BRKTHRU(0, &d_tt_mb, &d_finaltp, X`009`009`009 BRK$C_DEVICE, 0, 32, 0, BRK$C_USER16, 0, 0, 0)); X`009if (no_oper) X`009 check(SYS$SETPRV(0, &privs, 0, 0)); X `125 X check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, &broadcast_handler, V 0, X`009`009 &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X`125 X Xpost_term_reads()`009`009/* Read AST on real term */ X`123 X if (brkthru) `123 X`009check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, X`009`009 &broadcast_handler, 0, &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X `125 else `123 X`009check(SYS$QIO(0, tt_mb_chn, IO$_READVBLK, &tiosbmb, 0, 0, X`009`009 &tt_mb, TTMBSIZ, 0, 0, 0, 0)); X `125 +-+-+-+-+-+-+-+- END OF PART 5 +-+-+-+-+-+-+-+- -+-+-+-+-+-+-+-+ START OF PART 6 -+-+-+-+-+-+-+-+ X check(SYS$QIO(0, tt_chn, IO$_READVBLK, &tiosb, &tt_srv, TRUE, X`009`009 &input_char, 1, 0, 0, 0, 0)); X`125 X Xpost_pty_reads(n)`009`009/* Post read AST on Pseudo-term */ X int n; X`123 X char cr = '\r'; X X if (init) X`009return (0); X#ifndef USE_PTD X py_post`091n`093 = 1; X check(SYS$QIO(0, py_mb_chn`091n`093, IO$_READVBLK, &miosb`091n`093, &mb_ Vsrv, n, X`009`009 &py_mb`091n`093, MBSIZ, 0, 0, 0, 0)); X check(SYS$QIO(0, py_chn`091n`093, IO$_READVBLK, &piosb`091n`093, &py_srv V, n, X`009`009 &tpline`091n`093, LINESZ, 0, 0, 0, 0)); X#else X check(PTD$READ(0, py_chn`091n`093, &py_srv, n, tpline`091n`093-4 ,LINESZ V-4)); X#endif X if (proc_type`091n`093 == TOP) `123 X#ifndef USE_PTD X`009check(SYS$QIOW(0, py_chn`091n`093, IO$_WRITEVBLK, &tiosb, 0, 0, X`009`009 &cr, 1, 0, 0, 0, 0)); X`009if (tiosb.stats != SS$_DATAOVERUN) X`009 check(tiosb.stats); X#else X otpline`091n`093`0910`093 = cr; X check(PTD$WRITE(py_chn`091n`093,0,0,otpline`091n`093-4,1,0,0)); X/* should wait for completion? */ X#endif X `125 X`125 X Xint Xfire_up(n, nname, proc_mode)`009/* Fire up subprocess n */ X int n, proc_mode; X char nname; X`123 X int val, status; X name`091n`093 = nname; X procno`091nname - first_name`093 = n; X count`091n`093 = 0;`009`009/* Initialize buffer count */ X blocked`091n`093 = 0;`009`009/* It starts unblocked */ X bufmod`091n`093 = 0;`009`009/* Starts w/o buffering all */ X bufmod2`091n`093 = 0; X logmod`091n`093 = 0;`009`009/* no logging initially */ X logfd`091n`093 = 0;`009`009/* no fd either */ X py_post`091n`093 = 0; X mode`091n`093 = defmode; X pmode`091n`093 = defmode; X buflen`091n`093 = 0; X proc_type`091n`093 = proc_mode; X enable_hangup`091n`093 = 0; X pid`091n`093 = 0; X status = fix_a_tp(n);`009/* Set a pseudo terminal by TT info */ X#ifndef USE_PTD X check(SYS$CANCEL(py_chn`091n`093)); /* Don't need this Half of pseudo- Vter */ X#endif X val = (proc_type`091n`093 == TOP) ? status : X`009low_lib_spawn(n, finaltp`091n`093, &pid`091n`093, name`091n`093); /* Spa Vwn a subprocess */ X if (!bad(val)) `123 X`009if (auto_log) start_logging(n);`009/* if requested by /LOG */ X`009post_pty_reads(n);`009/* Set up AST */ X`009if (uw && !mac_command) X`009 uw_fun(P1_FN_NEWW `124 ((n + 1) & P1_WINDOW), 0, 0); X `125 else X`009comp_srv(n);`009`009/* Mark the process as non-existent */ X return (val); X`125 X Xinitialize() X`123`009`009`009`009/* Initialize everything */ X int j, item; X $DESCRIPTOR(d_boss_id, "BOSS$ID"); X $DESCRIPTOR(d_lnm_process, "LNM$PROCESS"); X X nalph = last_name - first_name + 1; X for (j = 0; j < nproc; j++) X`009name`091j`093 = '\0';`009`009/* Initialize variables */ X for (j = 0; j < nalph; j++) X`009procno`091j`093 = -1; X for (j = 0; j < nalph; j++)`123 X`009emitchr`091j`093`0910`093 = '\0'; X`009emitlen`091j`093 = 0; X`009echlen`091j`093 = BUFSIZE; X echnew`091j`093 = 0; X `125 X /* Save old value of BOSS$ID */ X j = SYS$TRNLNM(0, &d_lnm_process, &d_boss_id, X `009`009 &super_ac_mode, &trnlnm_item); X if (!bad(j) && trnlnm_string_len == 1) `123 X`009oboss_id = trnlnm_string`0910`093; X`009j = LIB$DELETE_LOGICAL(&d_boss_id, 0); X `125 X item = JPI$_PROCPRIV;`009/* Check whether have PHY_IO & OPER */ X check(LIB$GETJPI(&item, 0, 0, &priv, 0, 0)); X no_phy_io = !(priv`0910`093 & PRV$M_PHY_IO); X no_oper = !(priv`0910`093 & PRV$M_OPER); X item = JPI$_IMAGPRIV;`009/* Check whether we can do BRKTHRU */ X check(LIB$GETJPI(&item, 0, 0, &priv, 0, 0)); X brkthru = ((priv`0910`093 & PRV$M_OPER) `124`124 !no_oper); X priv`0910`093 = PRV$M_PHY_IO; X priv`0911`093 = 0; X privs`0910`093 = PRV$M_OPER; X privs`0911`093 = 0; X if (no_phy_io) X`009check(SYS$SETPRV(0, &priv, 0, 0)); X if (no_oper) X`009check(SYS$SETPRV(0, &privs, 0, 0)); X get_tt_info();`009`009/* Initialize terminal */ X if (uw) X`009uw_fun(P1_FN_MAINT `124 P1_MF_ENTRY, 0, 0); X start_up();`009`009`009/* Start up processes */ X if (recording) `123 X`009record_fd = creat(record_file, 0, "mbf=3"); X`009if (record_fd < 0) `123 X`009 perror(record_file); X`009 exit(0); X`009`125 X`009startclock(); X `125 X if (playback) `123 X`009playback_fd = open(playback_file, O_RDONLY, 0, "mbf=3"); X`009if (playback_fd < 0) `123 X`009 perror(playback_file); X`009 exit(0); X`009`125 X `125 X post_term_reads(); X`125 X X/* Next two routines taken from FILE program by Joe Meadows Jr. */ X Xlong int Xcli_present(s) X char *s; X`123 X static struct dsc$descriptor s_desc = `1230, DSC$K_DTYPE_T, DSC$K_CLASS_ VS, 0`125; X X s_desc.dsc$w_length = strlen(s); X s_desc.dsc$a_pointer = s; X return (cli$present(&s_desc)); X`125 X Xlong int Xcli_get_value(s1, s2) X char *s1, **s2; X`123 X static struct dsc$descriptor s1_desc = X `009`1230, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0`125; X static struct dsc$descriptor s2_desc = X `009`1230, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0`125; X static char null = '\0'; X static struct dsc$descriptor null_desc = X `009`1231, DSC$K_DTYPE_T, DSC$K_CLASS_S, &null`125; X long int status; X X s1_desc.dsc$w_length = strlen(s1); X s1_desc.dsc$a_pointer = s1; X X status = cli$get_value(&s1_desc, &s2_desc); X X if (status & 1) `123 X`009str$append(&s2_desc, &null_desc); X`009*s2 = s2_desc.dsc$a_pointer; X `125 else X`009*s2 = 0; X return (status); X`125 X Xprocess_command_line() X`123 X long int status, boss_len; X short int length; X $DESCRIPTOR(d_line, buf); X $DESCRIPTOR(d_cldline, buf); X $DESCRIPTOR(d_boss_term, "BOSS$TERM"); X $DESCRIPTOR(d_lnm_file_dev, "LNM$FILE_DEV"); X X strcpy(buf, "BOSS "); X boss_len = strlen(buf); X d_line.dsc$w_length = d_line.dsc$w_length - boss_len; X d_line.dsc$a_pointer = d_line.dsc$a_pointer + boss_len; X check(lib$get_foreign(&d_line, 0, &length, 0)); X buf`091length + boss_len`093 = '\0'; X d_cldline.dsc$w_length = length + boss_len; X status = cli$dcl_parse(&d_cldline, BOSS_CLD, 0, 0, 0); X if (bad(status)) X`009exit(STS$K_ERROR + STS$M_INHIB_MSG); X X status = cli_present("UW"); X uw = !bad(status); X X if (!uw) `123 X`009nproc = NPROCMAX; X`009defmode = 'b'; X`009first_name = 'A'; X`009last_name = 'Z'; X `125 else `123 X`009nproc = P1_NWINDOW; X`009defmode = 'p'; X`009first_name = '1'; X`009last_name = '7'; X `125 X X status = cli_get_value("COMMAND_CHARACTER", &retval); X if (bad(status)) `123 X`009if (!uw) X`009 ctlchar = 034;`009/* C-\ */ X`009else X`009 ctlchar = -1; X `125 else X`009sscanf(retval, "%d", &ctlchar); X if (ctlchar < (uw ? -1 : 0) `124`124 ctlchar > 0177 `124`124 ctlchar == V 032) `123 X`009printf("`091Illegal command character (%d); using C-\\ instead`093\n", X`009 ctlchar); X`009ctlchar = 034;`009`009/* C-\ */ X`009/* disallow C-z as a command character */ X `125 X if (ctlchar >= 0 && ctlchar < 040) X`009sprintf(ctlchar_str, "C-%c", tolower(ctlchar + 0100)); X else if (ctlchar == 040) X`009strcpy(ctlchar_str, "SPC"); X else if (ctlchar == 0177) X`009strcpy(ctlchar_str, "DEL"); X else if (ctlchar == -1) X`009strcpy(ctlchar_str, "---"); X else X`009sprintf(ctlchar_str, "%c", ctlchar); X X status = cli_get_value("BEGIN_PROMPT", &retval); X if (bad(status)) X`009strcpy(prompt_begin, ""); X else X`009strcpy(prompt_begin, retval); X X status = cli_get_value("END_PROMPT", &retval); X if (bad(status)) X`009strcpy(prompt_end, ""); X else X`009strcpy(prompt_end, retval); X X status = cli_get_value("DEFAULT_OUTPUT_FLAG", &retval); X if (!bad(status)) X`009defmode = tolower(retval`0910`093); X X status = cli_get_value("PROCESS_DEFAULT", &retval); X if (bad(status)) X`009defproc = CREATE; X else X`009defproc = ((retval`0910`093 == 'T') ? TOP : CREATE); X X status = cli_present("SWITCH_CREATE"); X switch_create = !bad(status); X X status = cli_present("FLOW_CONTROL"); X flow_control = !bad(status) `124`124 uw; X X status = cli_get_value("DELETE_CHARACTER", &retval); X if (bad(status)) X`009delete_char = 0177; X else X`009sscanf(retval, "%d", &delete_char); X if (delete_char < 0 `124`124 delete_char > 0177) `123 X`009printf("`091Illegal delete character (%d); using DEL instead`093\n", X`009 delete_char); X`009delete_char = 0177; X `125 X status = cli_get_value("AUTO_STUFF_STRING", &retval); X if (bad(status)) X`009def_stuff_len = 0; X else `123 X`009strcpy(def_stuff_buf, retval); X`009if (strlen(retval) > 0) X`009 strcat(def_stuff_buf, "\015"); X`009def_stuff_len = strlen(def_stuff_buf); X `125 X X status = cli_present("RECORD"); X recording = !bad(status); X if (recording) `123 X`009status = cli_get_value("RECORD", &retval); X`009if (bad(status)) `123 X`009 strcpy(record_file, "BOSS.RECORD"); X`009`125 else `123 X`009 strcpy(record_file, retval); X`009`125 X `125 X status = cli_present("PLAYBACK"); X playback = !bad(status); X if (playback) `123 X`009status = cli_get_value("PLAYBACK", &retval); X`009if (bad(status)) `123 X`009 strcpy(playback_file, "BOSS.RECORD"); X`009`125 else `123 X`009 strcpy(playback_file, retval); X`009`125 X `125 X status = cli_present("GEAR"); X if (!bad(status)) `123 X`009status = cli_get_value("GEAR", &retval); X`009if (!bad(status)) `123 X`009 char *cp = retval; X`009 while (*cp) `123 X`009`009*cp = tolower(*cp); X`009`009cp++; X`009 `125 X`009 if (!strncmp(retval, "infinite", strlen(retval))) `123 X`009`009printf("`091Boss: no delays in playback`093\n"); X`009`009gear = -1.0; X`009 `125 else `123 X`009`009gear = atof(retval); X`009`009if (gear <= 0.0) `123 X`009`009 printf("`091Boss: bad /GEAR value, assuming 1.0`093\n"); X`009`009 gear = 1.0; X`009`009`125 X`009 `125 X`009`125 X `125 X status = cli_present("LOCK"); X keyboard_locked = !bad(status); X X status = cli_present("LOG"); X auto_log = !bad(status); X/* Ensure logfile prefix gets set up whether or not there's autolog */ X strcpy(log_file_prefix, "BOSS"); X log_file_prefix_len = 4; X if (auto_log) `123 X`009status = cli_get_value("LOG", &retval); X`009if (bad(status)) `123 X`009 strcpy(log_file_prefix, "BOSS"); X`009 log_file_prefix_len = 4; X`009`125 else `123 X`009 /* watch out for overflow, need room for "x.log" */ X`009 log_file_prefix_len = strlen(retval); X`009 if (log_file_prefix_len >= sizeof(log_file_prefix) - 5) `123 X`009`009printf("`091Boss: log file prefix too long, ignored`093\n"); X`009`009strcpy(log_file_prefix, "BOSS"); X`009`009log_file_prefix_len = 4; X`009 `125 else `123 X`009`009strcpy(log_file_prefix, retval); X`009 `125 X`009`125 X `125 X X status = cli_present("QUIT_ON_IDLE"); X synchr_quit = !bad(status); X X status = SYS$TRNLNM(0, &d_lnm_file_dev, &d_boss_term, 0, &trnlnm_item); X if (bad(status)) X`009strcpy(trnlnm_string, "VT100"); X else X`009trnlnm_string`091trnlnm_string_len`093 = '\0'; X if (strcmp(trnlnm_string, "VT100") == 0) `123`009/* VT100 */ X`009clr = "\033`091r\033`0914l\033`091H\033`091J";`009/* Clear screen reset V scroll */ X`009bos = "\033`091r\033`0914l\033`09199;1H\n";`009/* Go to bottom of screen V */ X`009ceol = "\033`091K";`009/* Clear to end-of-line */ X`009ceoln = "\033`091K\r\n";`009/* Clear to end-of-line and newline */ X `125 else if (strcmp(trnlnm_string, "VT52") == 0) `123`009/* VT52 */ X`009clr = "\033H\033J"; X`009bos = "\033Y7 \n"; X`009ceol = "\033K"; X`009ceoln = "\033K\r\n"; X `125 else if (strcmp(trnlnm_string, "ADM3A") == 0) `123`009/* ADM3A */ X`009clr = "\032"; X`009bos = "\033=7 \n"; X`009ceol = " \010\010\010"; X`009ceoln = " \r\n"; X `125 else `123`009`009`009/* UNKNOWN */ X`009clr = "\r\n"; X`009bos = "\r\n"; X`009ceol = ""; X`009ceoln = "\r\n"; X `125 X`125 X Xint Xstart_up() X`123 X long int status, j, n; X char nname`09130`093, output_flags`09130`093, stuff_flag, odefmode; X X cur = -1; X if (!uw) X`009input_state = PENDING; X init = 1; X X status = cli_present("START_PROCESS"); X if (!bad(status)) `123 X`009stuff_flag = 1; X`009j = 0; X`009while (j < 30 && !bad(cli_get_value("START_PROCESS", &retval))) `123 X`009 if (strlen(retval) != 1) X`009`009break; X`009 nname`091j`093 = toupper(retval`0910`093); X`009 if (nname`091j`093 < first_name `124`124 nname`091j`093 > last_name) X`009`009break; X`009 j++; X`009`125 X`009n = j; X`009j = 0; X`009while (j < n && !bad(cli_get_value("OUTPUT_FLAGS", &retval))) `123 X`009 output_flags`091j`093 = tolower(retval`0910`093); X`009 j++; X`009`125 X`009while (j < n) `123 X`009 output_flags`091j`093 = defmode; X`009 j++; X`009`125 X`009for (j = 0; j < n; j++) `123 X`009 if (stuff_flag) `123 X`009`009status = cli_get_value("STUFF_STRING", &retval); X`009`009if (bad(status)) `123 X`009`009 stuff_flag = 0; X`009`009 strcpy(stuff_buf, ""); X`009`009`125 else `123 X`009`009 strcpy(stuff_buf, retval); X`009`009 if (strlen(retval) > 0) X`009`009`009strcat(stuff_buf, "\015"); X`009`009`125 X`009 `125 X`009 odefmode = defmode; X`009 defmode = output_flags`091j`093; X`009 status = mov_to(nname`091j`093, 0, stuff_buf, defproc); X`009 defmode = odefmode; X`009 if (bad(status)) X`009`009break; X`009 input_state = NORMAL; X`009`125 X `125 X init = 0; X for (j = 0; j < nproc; j++) X`009if (name`091j`093 > 0) X`009 post_pty_reads(j); X`125 X Xmain() X`123 X int exit_handler`0914`093 = `1230, quit, 0, &st`125; X X process_command_line(); X check(SYS$DCLEXH(&exit_handler));`009/* Define Exit handler (quit) */ X if (ctlchar >= 0 && ctlchar < 040) X`009printf("Begin BOSS %s\nType control-%c control-h for information\n", X`009 VERSION, tolower(ctlchar + 0100)); X else if (ctlchar < 0) X`009printf("Begin BOSS %s\n", VERSION); X else X`009printf("Begin BOSS %s\nType %s control-h for information\n", X`009 VERSION, ctlchar_str); X initialize(); X if (playback) `123 X`009/* playback mode: feed data from record file to tt_srv() */ X`009/* keep checking playback - tt_srv ASTs may reset it! */ X`009int i, j; X`009char buf`09180`093; X`009char *endbufp = &buf`09180`093; X X`009tiosb.stats = SS$_NORMAL;`009/* fool tt_srv */ X`009while (1 == 1) `123 X`009 if (!playback) X`009`009break; X`009 i = read(playback_fd, &input_char, 1); X`009 if (!i) X`009`009break; X`009 if (input_char != DELAY_ESC) `123 X`009`009/* normal char, process */ X`009`009tt_srv(FALSE); X`009 `125 else `123 X`009`009/* the escape char: read more into buf */ X`009`009i = read(playback_fd, &buf, 1); X`009`009if (!i) X`009`009 break; X`009`009if (buf`0910`093 == DELAY_ESC) `123 X`009`009 /* double escape: feed one */ X`009`009 input_char = DELAY_ESC; X`009`009 tt_srv(FALSE); X`009`009`125 else if (buf`0910`093 != '\n') `123 X`009`009 /* read a delay spec */ X`009`009 int delay; X`009`009 char *bufp = &buf`0911`093; X`009`009 while ((i = read(playback_fd, bufp, 1)) && (*bufp != '\n')) `123 X`009`009`009bufp++; X`009`009`009if (bufp == endbufp) `123`009/* overflow */ X`009`009`009 i = 0; X`009`009`009 break; X`009`009`009`125 X`009`009 `125 X`009`009 if (!i) X`009`009`009break;`009/* eof or overflow: error */ X`009`009 *bufp = '\0'; X`009`009 if (gear >= 0.0) `123`009`009/* ignore delay if gear<0 */ X`009`009`009delay = atoi(buf);`009/* get in 0.1 sec units */ X`009`009 delay = (int) (delay * 100.0 / gear); X`009`009`009msleep(delay); X`009`009 `125 X`009`009`125 X`009 `125 X`009`125`009`009`009/* end while */ X`009close(playback_fd); X`009/* playback ended, switch to interactive mode if no quit yet */ X`009playback = 0; X`009sprintf(buf, "%s`091Boss: playback ended`093%s", bos, ceoln); X`009term_msg(buf); X`009/* AST on real terminal already outstanding */ X`009/* Unlock keyboard, fall through into interactive mode */ X`009keyboard_locked = FALSE; X `125`009`009`009`009/* end if (playback) */ X /* Normal mode: driven by ASTs to tt_srv() */ X sys$hiber(); X`125 $ CALL UNPACK BOSS.C;279 1583823294 $ create/nolog 'f' Xmodule boss_cld Xdefine verb boss X qualifier command_character, negatable, default, X value(default="28",type=$number) X qualifier delete_character, nonnegatable, default, X value(default="127",type=$number) X qualifier start_process, nonnegatable, X value(required,list) X qualifier stuff_string, nonnegatable, X value(required,list) X qualifier output_flags, nonnegatable, X value(required,list,type=output_flag) X qualifier auto_stuff_string, negatable, X value(required) X qualifier begin_prompt, negatable, X value X qualifier end_prompt, negatable, default, X value(default="> ") X qualifier default_output_flag, nonnegatable, X value(type=output_flag) X qualifier switch_create, negatable X qualifier process_default, nonnegatable, default, X value(required,type=process_type) X qualifier flow_control, negatable X qualifier uw, negatable X qualifier record, nonnegatable, X value(type=$outfile) X qualifier playback, nonnegatable, X value(type=$infile) X`009qualifier gear, nonnegatable, X`009`009value(default="1.0") X`009qualifier log, nonnegatable, X`009`009value X`009qualifier lock, negatable X`009qualifier quit_on_idle X Xdisallow (record and playback) Xdisallow (lock and not playback) X Xdefine type output_flag X keyword b X keyword o X keyword p X keyword w X Xdefine type process_type X keyword top_level X keyword subprocess, default $ CALL UNPACK BOSS_CLD.CLD;33 2084663964 $ create/nolog 'f' X$! Procedure for compiling and linking BOSS. X$! X$ cc boss X$ set command/object boss_cld X$ link/notraceback boss,boss_cld,sys$input/opt Xsys$library:vaxcrtl/share $ CALL UNPACK BOSS_BUILD.COM;2 855795594 $ create/nolog 'f' X$! Procedure for installing BOSS. This goes into the system startup file. X$! X$ boss_dir = "usr:`091utility`093"`009! Edit to point to where BOSS.EXE resi Vdes X$ install = "$install/command_mode" X$ if f$file("''boss_dir'boss.exe","known") then install delete 'boss_dir'bo Vss X$ install create 'boss_dir'boss/priv=(phy_io,oper)/header/open/shared $ CALL UNPACK BOSS_INSTALL.COM;1 1029728184 $ v=f$verify(v) $ EXIT