.title CCL .ident /V8.0B/ .enabl LC .NLIST BEX .SBTTL Introduction ;+ ; JAMES G. DOWNWARD ; KMS FUSION, INC ; 3941 RESEARCH PARK DR. ; ANN ARBOR, MICH ; 313-769-8500 ; ; CCL is the composite work of many authors. The origional version was ; written by Richard Kirkman and was in Fortran. He later hand coded it from ; Fortran into Macro-11. KMS converted it for RSX11M V3.1 to use an MCR driver ; rather than adding an executive directive. Later KMS updated it to use the ; V3.2 SPAWN directive. While we were at it we added a number of other useful ; features found in DEC's TDX catchall task (best of both worlds). Angle Li ; then did a major rewrite to comment the code, make it flow smoothly, and ; to add some enhancements. We retaliated by adding a few more features. Then ; Paul Sorenson did another major rewrite to add more sophisticated parsing, ; DCL like commands, and a general internal table driven section. Again ; insprired, we added a few more features, and fixed some bugs. ; ; This program is the composite of two programs. One part uses a list of pre- ; defined commands(LIST, TYPE, DELETE...etc.) and turns them into MCR commands ; to the utilities. This part was paterned after DEC'S TDX or catchall task. ; It's included in the section 'DCL' at the end of CCL.MAC. ; ; The second part of the program consists of code to open a file ; (USERCCL.CCL or SYSCCL.CCL) and see if the command entered corresponds ; to a command entered in the file. First the file USERCCL.CCL ; on the user's UIC and SY: is tried. If either the file does not exist ; or the command is not found, the scan is repeated using SYSCCL.CCL. ; ; The program starts out by seeing if it got a valid command line from MCR. ; If it did, it calls the DCL subroutine which checks to see if it matches ; the command in the command table. Note that if the first three letters ; match, DCL assumes it is a match, and will field the command, so commands ; which have the first three letters matching in a .CCL file will do no good ; at all. If a match is found the command is spawned to MCR, and ...CA. will ; stop itself until the command is executed and then will exit with the ; appropriate status. ; ; If DCL subroutine does not find the command a direct return is made to CCL ; which proceeds to open the .CCL files, and search for a command which ; matches up to the first 8 letters. If a match is found, the prototype ; command line in the file is decoded, fleshed out, and spawned to MCR. ; If the command prototype ends with a %$ (signifying ESC) the CCL will exit ; without waiting for the MCR command to finish executing. Otherwise CCL will ; hang around until the command spawned to MCR has finished. ; ; ; VERSION 7.0B/C ; ; Note on Version 7.0B: Major modifications have been made to the internal ; workings of CCL, but the ultimate result should appear exactly the same as ; previous 2 releases of CCL from KMS Fusion via DECUS RSXSIG. Several more ; enhancements have been added, including: 1) prior to opening USERCCL.CCL, ; CCL will check an internal "file" in .PSECT $TABLE which should be setup ; exactly as a CCL file would be (alternative to DCL which can be easily ; modified), 2) If no match for keyword is found, CCL will attempt to spawn ; ...CA2 as a "catchall" task for CCL, 3) 3 more parameters have been added-- ; %0%=leading switches, %B%=string up to first major delimiter (currently only ; space) %C%=string from first major delimiter to end -- these were added ; to make supporting RT-11 V3 style commands easier. ; ; Version 8.0 ; ; RSX11M V4.0 supports alternate CLI's. This version of CCL may either be ; installed as a catchall task or as a CLI. To install CCL as a CLI, ; ; INS $CCL/TASK=...CCL/CLI=YES ; CLI /INIT=CCL/DPR="<15><12>/CCL>/" ; CLI /ENABLE=CCL ; ; If the system does not support CLI's, none of the above will work but CCL ; will still work as the catchall task ...CA. CCL also uses the RPOI$ ; directive where possible so that a version of CCL (...CA.) does not have ; to be left lying about to maintain the OCB linkage. If CCL is to be used ; as a CLI, the system CCL file for use as a CLI should be created as ; ; LB1:[1,5]SYSCLI.CCL ; ; Nasty warning messages appear if the file is missing. The command flow of ; CCL is altered somewhat if it is a CLI. If the command is looked for ; (in order) in ; Internal table ; SY0:[UIC]USERCLI.CCL ; LB1:[1,5]SYSCLI.CCL ; ; If not found in LB1:[1,5]SYSCLI.CCL, the command line is sent to MCR, the ; catchall task for CCL. By installing CCL as a CLI, all MCR commands can ; be redefined. Also the responsiveness of frequently used CCL commands is ; improved. ; ; ;- .SBTTL The original CCL ; ; Original author: R. J. KIRKMAN ; ; The main routine also requires SPAWN, LOOKUP, FIXUP, & GETLIN ; ; MODIFIED BY: ; ??-???-78 J. Downward Modified to use MCR driver for V3.1 ; ; 15-MAR-79 J. DOWNWARD ADD VARIOUS ERROR MESSAGES, TEST FOR ; LINES TOO LONG, AND FOR SPEED BUILD IN ; ALL KINDS OF DCL-LIKE COMMANDS. ; (EG. LIST, DIR, SPOOL, TRUNCATE, ; PURGE, DELETE., ETC.) ; ; 24-SEP-79 J. DOWNWARD ADD %U,'G%,%G,%T TO DECODED VARIABLES ; ADD MULTIPLE LINE CCL COMMANDS AND A ; ABILITY FOR CCL TO WAIT FOR A SPECIFIC ; TASK TO EXIT ; ; 10-Jan-80 A. Li Performed massive edit on all source ; U of Miami files and made the program legible. ; Also made error messages upper/lower ; and lower case. Conditionalized ; generation of DCL and the PIP subset ; of DCL. Added %A - pass entire command ; line (except the keyword). ; ; Fall 80 J. Downward Bells and whistles. ; ; 10-Mar-81 P. Sorenson Rewrote much of CCL and changed ; MSU handling of parameters by using pile ; of pointers. ; Added %0 - leading switches, e.g. ; BRU/REW/VER . Added %B - first set ; of parameters (up to first space). ; Added %C - second set of parameters, ; from %B to end, minus delimiter. ; Added lookup from internal "file" as ; a compromise between DCL and .CCL ; files. USERCCL.CCL is opened on users ; protection (logon) UIC rather than ; default UIC-- most often, but not ; always, the same. ; ; Paul Sorenson ; Department of Physiology ; Michigan State University ; E. Lansing, MI 48824 ; 517-355-5125 ; ; 22-MAR-81 J. DOWNWARD Added %R (ring terminal bell on exit) ; JGD04 to provide same functionality as the ; old style (pre V7.0) %B. (JGD05) ; ; 23-MAR-81 J. Downward Added %D (debug). If encountered the ; JGD05 expanded command line (to that point) ; will be printed. ; ; JGD06 Conditionalized DEBUG code. Added ; %Q so can exit CCL without sending ; command to MCR if a required input ; field is defaulted with a null. ; ; JGD07 Conditionalized (on $DCLX) out those ; DCL commands which could easily be ; replaced by the new Internal Table ; parsing. Added %P to print a line ; to the terminal with no additional ; messages. ; ; JGD08 Required changes for RPOI$ support ; in SPAWN.MAC for RSX11M V4.0. ; CCL V7.0C ; ; Version V8.0 ; ; JGD09 Changes so that CCL can be an ; Oct 24,1981 alternate CLI. ; ; JGD10 Convert lowercase to upper case if ; the command input is from GCII$. ; .MCALL OPEN$R,FDBDF$,FDRC$A,CLOSE$,EXIT$S,QIOW$S .MCALL FDOP$A,FSRSZ$,DIR$,EXST$S,GTSK$S,GLUN$ .MCALL QIOW$C,CNCT$,STSE$S,CLEF$S .MCALL GCII$,GCCI$ ;JGD09 ; Move conditional assembly stuff out to its own file for easier ; manipulation. ; ; .SBTTL Define assembly conditionals ; ;$DCL = 0 ; Enable DCL ;ALI ;$PIP = 0 ; Enable PIP subset of DCL ;ALI ;$DCLX = 0 ; Enable MCR info subset of DCL ;JGD07 ;$LB0 = 0 ; Redefine device for SYSCCL.CCL to LB0: ;PRS ; DEBUG conditionals ;JGD06 ;$DBG = 0 ; Define for debug version PART 0 ;JGD06 ;$DBG1 = 0 ; " " " " PART 1 ;JGD06 ;$DBG2 = 0 ; " " " " PART 2 ;JGD06 ;$DBG3 = 0 ; " " " " PART 3 ;JGD06 ;$DBG4 = 0 ; " " " " PART 4 ;JGD06 ;$DBG5 = 0 ; " " " " PART 5 ;JGD06 ;$DBG6 = 0 ; " " " " PART 6 ;JGD06 ; ; Define buffer length ; PARLNG = 256. ; 256 bytes for all %n% ; ; Further misc. definitions ; CR = 15 ; LF = 12 ; ESC = 33 ; SPA = 40 ; Blank SWTCH = 57 ; / -- standard RSX/RT switch delimiter COMMA = 54 EQUAL = 75 LANGLE = 74 RANGLE = 76 QNMRK = 77 LBRACK = 133 RBRACK = 135 UNDSCR = 137 PCNT = 45 PLUS = 53 MINUS = 55 STAR = 52 ; ; The program reads in turn the user file SY:USERCCL.CCL and then the system ; file LB1:[1,5]SYSCCL.CCL (or LB0: if defined $LB0 in conditional assembly ; file) in a specific directory. ; LUN 1 is used for the files and LUN 2 for error reporting and ; for asking for parameters. ; FSRSZ$ 1 ; One file only! ; ; Note this was FORTRAN common - this is shared by ALL routines. ; .PSECT .$$$$.,rw,d,ovr,gbl ; ; The common data area for the three routines FIXUP,LOOKUP and the MAIN program. ; CMD: .blkb 80. ; Output command line CLIBF: .BLKW 3. ; Occupies the next 88 bytes ;JGD90 MCRL: .word 0 ; Length of mcr line MCR: .blkb 80. ; MCR line CLILN = .-CLIBF ; Length of CLI get command line buffer ;JGD09 KEYL: .word 0 ; Length of keyword KEYB: .WORD MCR ; Keyword buffer address ;PRS01 ; ; P defines a buffer for holding parameters. All parameters included ; in the original MCR line are not held in P, rather, they remain ; in MCR with their pointers set to the appropriate values for their ; subsequent recovery. Therefore, P only holds parameters input in ; response to a "query" line. The current definition of 256. bytes ; is probably excessive -- PRS 3/81 ; P: .BLKB 256. ; Define parameter buffer ; PRS NEXTP: .WORD P ; Points to next free spot in P ; PRS ; ; Parameter pointers consist of: ; 1st word = byte count, ; 2nd word = address of parameter string. ; PRS 3/81 ; PNTR0: .WORD 0,0 ; Parameter 0 pointer; leading switches PNTR1: .WORD 0,0 ; Parameter 1 pointer PNTR2: .WORD 0,0 ; Parameter 2 pointer PNTR3: .WORD 0,0 ; Parameter 3 pointer PNTR4: .WORD 0,0 ; Parameter 4 pointer PNTR5: .WORD 0,0 ; Parameter 5 pointer PNTR6: .WORD 0,0 ; Parameter 6 pointer PNTR7: .WORD 0,0 ; Parameter 7 pointer PNTR8: .WORD 0,0 ; Parameter 8 pointer PNTR9: .WORD 0,0 ; Parameter 9 pointer PNTRA: .WORD 0,0 ; Parameter A pointer; MCR line minus keyword PNTRB: .WORD 0,0 ; Parameter B pointer; 1st major parameter set PNTRC: .WORD 0,0 ; Parameter C pointer; 2nd major parameter set PMIN: .WORD 0 ; Min # of parameters allowed PMAX: .WORD 0 ; Max # of parameters to prompt for EXSTAT: .WORD EX$SUC ; Assume sucessful exit DUIC: .WORD 0 ; For terminal (default) UIC ;JGD03 GLBUF: .BLKB 12. ; For terminal unit ;JGD03 INFOBF: .BLKW 7. ; Buffer to recieve CLI information ;JGD09 INFOLN = .-INFOBF ; Make it 7 words long ;JGD09 GCIIBF: .BLKW 24. ; Buffer to inquire about CLI ;JGD09 GCIILN = .-GCIIBF ; Length of buffer ;JGD09 .PSECT $VARS,RW,D,CON,LCL ; ; Error messages and prompts ; GTBUF: .BLKW 16. ; Parameters returned by "get task parameters" STATUS: .BLKW 8. ; For status return from "connect to task" IOSTS: .BLKW 2 ; Status block for prompting (QIO IO.RPR) LINTYP: SAVTYP::.BYTE 0 ; Save 1st char of CCL file action line (* or +);JGD08 MORE: .BYTE 0 ; Flag set if next line of CCL file is a continuation ; of previous line INUIC: .WORD 0 ; Flag set when in/cleared when out of UIC field NOSTOP::.WORD 0 ; Flag set to non-zero by FIXUP when command ; template includes %$ to allow exitting ; before spawned task exits. RING:: .WORD 0 ; Flag to indicate that the terminal bell ;JGD04 ; when CCL exits ;JGD04 DBGFLG::.WORD 0 ; Flag, when set the CCL command will print out ;JGD05 QTFLAG::.WORD 0 ; Set if %Q, quit if required parm missing ;JGD06 QUIT:: .WORD 0 ; Set if any default parameter is nulled ;JGD06 PRINT:: .WORD 0 ; Set if %P (print line to TI:) found ;JGD07 CLIFLG::.WORD 0 ; Set if we are a CLI ;JGD09 ; ; Error message definitions ; MSG2: .IFNDF $LB0 .ASCII /CCL -- Error reading LB1:[1,5]SYS/ ;JGD01 MSG2A: .ASCIZ /CCL.CCL, the CCL system file/<15><12> ;JGD01 .IFF .ASCII /CCL -- Error reading LB0:[1,5]SYS/ ;JGD01 MSG2A: .ASCIZ /CCL.CCL, the CCL system file/<15><12> ;JGD01 .ENDC MSG3: .ASCIZ /CCL -- No command line !/ ;JGD01 MSG4: .ASCII /? ?/ ;JGD01 .ASCIZ /CCL -- MCR syntax error, unknown or ambiguous command/ MSG5: .ASCIZ /CCL -- CCL command too long/ MSG6: .ASCIZ /CCL -- SPAWN failure to MCR/ MSG7: .ASCIZ /CCL -- Expanded command line is:/ ;JGD05 EM2: .ASCIZ /CCL -- Command line too long/ EM3: .ASCIZ /CCL -- Syntax error/ EM4: .ASCII /CCL -- Task / ;JGD03 TSKNAM: .ASCII /XXXXXX/ ;JGD03 .ASCIZ / not active or not found/ ;JGD03 EM5: .ASCIZ /CCL -- GCII$ failed/ ;JGD09 EM6: .ASCIZ /CCL -- GCCI$ failed/ ;JGD09 PRMPT: .ASCIZ /CCL -- Command line to CCLCLI missing/<15><12> ;JGD09 BELMSG: .ASCIZ <7> .EVEN .if df $DCL ; Only if we want it ;ALI .if df $PIP ; Only if we really want ;ALI ; ; PIP commands for DIR,LIST, DELETE, SPOOL, PURGE, TRUNCATE, UNLOCK ; TYPMSG: .ASCIZ /PIP TI:=/ PIPHD: .ASCIZ /PIP / DELMSG: .ASCIZ \/DE/LD\ DIRMSG: .ASCIZ \/LI\ PURMSG: .ASCIZ \/PU\ SPOMSG: .ASCIZ \/SP\ TRUMSG: .ASCIZ \/TR\ CREMSG: .ASCIZ \=TI:\ FREMSG: .ASCIZ \/FR\ SORMSG: .ASCIZ \SRD \ .EVEN .endc; $PIP ;ALI .endc; $DCL ;ALI ; ; Define the files that may be accessed ; LBDEV: .IIF NDF $LB0 .ASCII /LB1:/ ; Dev for system file .IIF DF $LB0 .ASCII /LB0:/ ; Alternate device for system file SYDEV: .ASCII /SY:/ ; Dev for userccl file SYUIC: .ASCII /[1,5]/ ; UIC for my system file SYFIL: .ASCII /SYSCCL.CCL/ ; Name of my system file USRUIC: .BLKB 9. ; Will hold users protection (logon) UIC USRFIL: .ASCII /USERCCL.CCL/ ; Name of user's files .EVEN SYSDST: .WORD 4,LBDEV,5,SYUIC,10.,SYFIL USRDST: .WORD 3,SYDEV,9.,USRUIC,11.,USRFIL ; ; FDB for our CCL spec file ; FDB:: FDBDF$ FDRC$A ,INBF,80. FDOP$A 1,,,FO.RD!FA.SHR ; ; Input buffer for spec lines ; INBF:: .BLKB 80. ; ; Get terminal characteristics and connect to task directives ; GLUN: GLUN$ 2,GLBUF CNCT: CNCT$ XX,4,,STATUS ; Connect to task ; ; Get CLI directives ; GETCII: GCII$ GCIIBF,GCIILN,, GTCMCI: GCCI$ CLIBF,CLILN,INFOBF,INFOLN,,GC.CEX ; Exit if no CMD .PAGE .SBTTL CCL - Root section .PSECT $CODE1,RW,I,CON,LCL CCL: GTSK$S #GTBUF ; Get our task parameters ;JGD DIR$ #GLUN ; Get our terminal LUN information ;JGD MOV GTBUF+G.TSDU,R3 ; Get protection (logon) UIC MOV #1,R4 ; Set up for no zero suppression, include [,] MOV #USRUIC,R2 ; Fetch address to put ASCII UIC CALL .PPASC ; Convert UIC to ASCII for later--User's file MOV GTBUF+G.TSPC,DUIC ; Get default UIC (may or may not be ; the protection UIC) CMP #^RCA.,GTBUF ; If we are the catchall, CA.XXX skip ;JGD09 BEQ 4$ ; CLI stuff so can behave correctly ;JGD90 CMP #^RCA.,GTBUF+2 ; If we are the catchall, ...CA., skip ;JGD09 BEQ 4$ ; the CLI sturr so can behave normally ;JGD09 DIR$ #GETCII ; GET CLI INFORMATION ;JGD09 CMP $DSW,#IS.SUC ; Did we succeed ;JGD09 BEQ 2$ ; if EQ, Yes ;JGD09 CMP $DSW,#IE.SDP ; Is alternate support in system? ;JGD09 BEQ 4$ ; If EQ, No, MCR is only CLI ;JGD09 MOV #EM5,R0 ; ELSE TELL USER directive failed ;JGD09 JMP TYPERR ; WRITE OUT ERROR AND EXIT ;JGD09 ; ;JGD09 ; At this point we should know what our CLI is ;JGD09 2$: CMP GCIIBF+G.CICL,#^RMCR ; Is it MCR ;JGD09 BNE 6$ ; If not MCR, use as alternate CLI ;JGD09 ; ;JGD09 ; Now we know that MCR is this terminal's CLI, so we must be the ;JGD09 ; catchall task ...CA., so get the MCR command line 4$: MOV (PC)+,R1 .BYTE 127.,41. ; Setting up for DIR$ GMCR MOV R1,MCRL DIR$ #MCRL ; GET COMMAND LINE MOV @#$DSW,MCRL ; GET LENGTH OF COMMAND LINE BR COMCOD ; SKIP CLI STUFF ;JGD09 ; ;JGD09 ; If we get here we must be an alternate CLI, so get the command line ;JGD09 ; and behave in a fashon consistent with our lofty status. ;JGD09 ; More importantly, change the default files we open to be ;JGD09 ; LB1:[1,5]SYSCLI.CCL and SY:[UIC]USERCLI.CCL. ;JGD09 ; ;JGD09 6$: INC CLIFLG ; Show we are a CLI ;JGD09 MOVB #'L,SYFIL+4 ; Set to look on LB1:[1,5]SYSCLI.CCL ;JGD09 MOVB #'I,SYFIL+5 ; if we are a CLI ;JGD09 MOVB #'L,MSG2A+1 ; Tailor error message ;JGD09 MOVB #'I,MSG2A+2 ; to make pretty ;JGD09 MOVB #'L,USRFIL+5 ; Set to look on SY:[UIC]USRCLI.CCL ;JGD09 MOVB #'I,USRFIL+6 ; if we are a CLI ;JGD09 CLI: DIR$ #GTCMCI ; Get command line, Exit if none. ;JGD09 BCC 8$ ; IF CC COMMAND LINE EXISTS ;JGD09 MOV #PRMPT,R0 ; IF NO COMMAND EXISTS PROMPT ;JGD09 JMP TYPERR ; WRITE OUT PROMPT AND EXIT ;JGD09 8$: ; ;JGD09 MOVB CLIBF+G.CCCT,MCRL ; GET # OF CHARACTERS ;JGD09 MOV #CLIBF+G.CCBF,R0; ADDRESS OF START OF BUFFER ;JGD09 ADD CLIBF+G.CCCT+1,R0; POINT AT END OF BUFFER ;JGD09 MOVB #15,(R0) ; TERMINATE WITH A ;JGD09 ; ; Get command line for CLI's does not convert Lower case to Upper case ; so we must do it ourselves, sigh! ; MOV MCRL,R2 ; We'll need this for loop ;JGD10 MOV #CLIBF+G.CCBF,R0; Address of start of buffer ;JGD10 10$: MOVB (R0)+,R1 ; Get character ;JGD10 CMPB R1,#141 ; Is it lower case ;JGD10 BLT 15$ ; If LT, no, check next char ;JGD10 CMPB R1,#172 ; Maybe, is it in right range ;JGD10 BGT 15$ ; If GT, no it isn't, try next char ;JGD10 SUB #40,R1 ; Yes it is, make it into upper case ;JGD10 15$: MOVB R1,-1(R0) ; Return converted character to buffer ;JGD10 SOB R2,10$ ; Loop until last character done ;JGD10 ; ; Whether we are a CLI or a catchall, we wind up here. ; ; COMCOD: TST MCRL ; Any command line specified? BGT CCL1 ; Branch if one exists ; ; No command line, print a message and exit with severe status ; MOV #MSG3,R0 ; Get appropriate error message JMP TYPERR ; Write it out and exit ;ALI ; ; Call DCL subroutine. DCL returns only if command is not a DCL one. ; CCL1: ; .IFDF $DBG ; If debugging ;JGD06 MOV #MCR,R0 ; ;PRS MOV MCRL,R1 ; ;PRS QIOW$S #IO.WAL,#2,#1,,,, ;PRS .ENDC ; ;JGD06 .IFDF $DCL ; Sometimes useful CALL DCL ; Is it a built-in command? .ENDC; $DCL ; ; ; Split out command name from command line ; CLR PNTRA ; Clear length of MCR line minus keyword MOV #MCR,R0 ; Fetch start address of MCR line MOV R0,KEYB ; Define keyword start address ;PRS01 CLR R1 ; Use R1 as counter for moving keyword ;PRS01 BR 5$ ; Branch, 1st character must be in keyword 1$: CMPB (R0),#SPA ; Check for delimiter BLT 25$ ; Branch if end of line delimiter BEQ 20$ ; Branch if space delimiter CMPB (R0),#SWTCH ; Check if at switch ('/') BEQ 22$ ; Branch if yes CMP R0,#MCR+8. ; At eight characters yet BHIS 7$ ; Branch if yes, skip rest of keyword 5$: MOVB (R0)+,MSG4+3(R1) ; Move character to message buffer ;PRS01 BR 8$ ; and get next character ;PRS01 7$: INC R0 ; Skip to next character 8$: INC R1 ;PRS01 BR 1$ ; and continue ; ; Keyword found, define start of MCR line minus keyword as parameter A. ; If at space delimiter, bump pointer past delimiter; if at switch ; delimiter, don't bump pointer; if neither enter at 25$, ; there is no parameter A, leave its length cleared. ; 20$: INC R0 ; Skip over space 22$: MOV R0,PNTRA+2 ; Save pointer for parameter A MOV MCRL,PNTRA ; Compute length SUB #MCR,R0 ; of MCR line SUB R0,PNTRA ; minus keyword 25$: ;PRS01 MOV R1,KEYL ; Save length of keyword .IFDF $DBG1 ; ;JGD06 MOV #MCR,R0 ;PRS MOV MCRL,R1 ;PRS QIOW$S #IO.WAL,#2,#1,,,, ;PRS MOV KEYB,R0 ;PRS01 MOV KEYL,R1 ;PRS QIOW$S #IO.WAL,#2,#1,,,, ;PRS MOV PNTRA+2,R0 ;PRS MOV PNTRA,R1 ;PRS QIOW$S #IO.WAL,#2,#1,,,, ;PRS .ENDC ;$DBG ;JGD06 ; ; New starting point for keyword matching. If $DCLTB is defined, ; will first scan an internal "file" on LUN 0. ; START: .IF DF $DCLTB ; ; Look for internal file - make it look like a file by using ; FDB to store next record pointer and record length. Do a pseudo ; OPEN here -- opened on LUN 0, positioned at first record, 0 bytes ; in current record. ; CLR FDB+F.NRBD ; Set up initial length MOV #$TABLE,FDB+F.NRBD+2 ; Set up start address of $TABLE CLRB FDB+F.LUN ; Specify LUN 0 CALL LOOKUP ; Try to match keyword TST R0 ; Check return status BMI KEYFND ; Branch if match successful .ENDC ; ; Look for USERCCL.CCL ; USROPN: MOV #SYSOPN,R2 ; Error return if "USERCCL.CCL" doesn't exist MOV #USRDST,R1 ; Data set descriptor CALL OPEN ; Try and open it ; ; Found a user file , lookup the keyword in there ; CALL LOOKUP ; Try and find the keyword TST R0 ; Is it there? BMI KEYFND ; Branch if keyword found ; ; Keyword not found, close the file and look for it in "SYSCCL.CCL" ; CALL CLOS ; FCS close ; ; Try opening "SYSCCL.CCL" ; SYSOPN: TST CLIFLG ; Are we a CLI ;JGD09 BEQ 8$ ; If EQ, no ;JGD09 MOV #5$,R2 ; Come back here if error ;JGD09 BR 10$ ; Try to open SYSCLI.CCL ;JGD09 5$: MOV #MSG2,R0 ; Print warning message ;JGD09 CALL TYPEIT ; Write it out but don't exit ;JGD09 BR CTCHAL ; Instead, still send it to MCR ;JGD09 8$: MOV #OPNFL,R2 ; Error return prints a message and exits 10$: MOV #SYSDST,R1 ; "SYSCCL.CCL" dataset descriptor CALL OPEN ; Perform the open CALL LOOKUP ; Find the keyword TST R0 ; Is it there? BMI KEYFND ; Branch if keyword found ; ; If found in system file deal in exactly same way as user file. ; If not then close file and check was last char of keyword ; a "?". The utility of this construction is not completely clear ; to me (P. Sorenson) and I don't know if something was lost in ; translation. I will implement help syntax as follows...move ? into ; keyword buffer alone and redefine the original MCR keyword plus ; any other stuff on the line as a new parameter A. The code to use ; in the .CCL or internal files can then be : $1100? *HELP %A%. ; For an MCR line like PIP?, this should be recoded to HELP PIP. ; CALL CLOS ; Close SYSCCL.CCL MOV KEYL,R0 ; Get keyword length CMPB MCR-1(R0),#QNMRK ; Ends with "?" ? ;PRS01 BEQ HELP ; Branch if yes, get help syntax ; ; If keyword isn't for help, try spawning MCR line off to ...CA2, as the ; catchall task for ...CA. (CCL). Send command line to SPAWN routine ; with command start address in R0, command length in R1, and non-zero value ; in R2 to exit immediately after successful spawn. ; CTCHAL: MOV #MCR,R0 ; Fetch start address for original MCR line MOV MCRL,R1 ; and its byte count MOV #1,R2 ; Set R2 non-zero; exit at once after spawn TST CLIFLG ; Are we a CLI ;JGD09 BEQ 15$ ; If EQ, no, try second catchall ;JGD09 CALL PUTMCR ; Use MCR as a catchall (Ha, Ha, Ha!) ;JGD09 JMP FINISH ; MCR has to take it else ...CA. will ;JGD90 15$: CALL PUTCA2 ; Try spawning to ...CA2 ;JGD09 BCS 20$ ; Branch if spawn failed, simply indicate ; unknown command JMP FINISH ; ...CA2 took it (amazing), exit CCL 20$: MOV #MSG4,R0 ; Set up error message JMP TYPERR ; Type error message and exit ; ; Generate HELP command for keyword; make "?" the new keyword and set ; parameter A (%A%) to entire command line (including keyword). ; HELP: MOVB #SPA,MCR-1(R0) ; Get rid of ? from MCR line MOV #1,KEYL ; Set keyword length to 1 MOVB #QNMRK,P ; Set keyword to "?" ;PRS01 MOV #P,KEYB ; P array will hold keyword now ;PRS01 MOV MCRL,PNTRA ; Redefine parameter A length MOV #MCR,PNTRA+2 ; and start address BR START ; New command to interpret ; ; Keyword found, clear lengths of parameters 0-9, B-C ; KEYFND: CLR INUIC ; Not in UIC field MOV #P,NEXTP ; Define start address of P array MOV #PNTR0,R0 ; Fetch address of parameter 0 MOV #10.,R1 ; Define # parameters to clear 3$: CLR (R0)+ ; Clear length ADD #2,R0 ; Skip start address SOB R1,3$ ; and continue till done CLR 4(R0) ; R0 points to length of param A, use index CLR 10(R0) ; to clear lengths of B and C ; ; Register usage for following section: ; R0 = pointer into MCR line ; R1 = # characters left in MCR line ; R2 = offset to parameter working on ; CLR R2 ; Set offset to 0, working on parameter 0 MOV (R0)+,R1 ; Recover length of MCR line left to encode BLE DONE ; Branch if nothing here MOV (R0),R0 ; Recover current pointer into MCR line ; CMPB -1(R0),#SPA ; Was previous character a space? ; BEQ 20$ ; Branch if yes, no parameter 0 CMPB (R0),#SWTCH ; Is current character a "/"? BNE 20$ ; Branch if NE, no parameter 0 MOV R0,PNTR0+2 ; Define start address for parameter 0 10$: CMPB (R0)+,#SPA ; Space (or end of line) only legal delimiter BLE 15$ ; Branch on delimiter DEC R1 ; Readjust length left in MCR line BR 10$ ; and check again 15$: MOV R0,PNTR0 ; Copy current position in MCR line DEC PNTR0 ; and backup to delimiter SUB PNTR0+2,PNTR0 ; Subtract start address to define byte count TST R1 ; Anything still in MCR line? BLE DONE ; Branch if done 20$: MOV R0,PNTRB+2 ; Copy current position as parameter B start MOV #PNTR1,R2 ; Fetch address for parameter 1 pointer SCAN: MOV R0,2(R2) ; Stash current position as parameter n start 1$: ; ; Look at current character ; CMPB (R0),#LBRACK ; Is it start of the UIC? BNE 3$ ; No, branch MOV #-1,INUIC ; Set UIC flag 3$: CMPB (R0),#RBRACK ; Is it the end of the UIC field? BNE 5$ ; No, branch CLR INUIC ; Yes, clear UIC flag ; ; Check for ' ', '=', '<', '_', ',' (Legal separators) ; If ',' then check if we are in a UIC field ; 5$: CMPB (R0),#SPA ; Is it a blank? BLE MAJSEP ; Branch if it is CMPB (R0),#EQUAL ; Equal sign? BEQ SEP ; Branch if so CMPB (R0),#LANGLE ; UNIX redirect? BEQ SEP ; Could be CMPB (R0),#UNDSCR ; Underscore? BEQ SEP ; Branch if underscore CMPB (R0),#COMMA ; Comma? BNE 20$ ; Branch if it is not TST INUIC ; Found a comma, are we in a UIC field? BGE SEP ; Branch if not in uic, comma is delimiter ; ; Character is not a separator, skip over it ; 20$: INC R0 ; Step over character DEC R1 ; Readjust # characters left INC (R2) ; Add 1 to byte count of current parameter BR 1$ ; and do it again ; ; Major separator found (space) finish defining parameter B and ; define parameter C as everything thats left. Then finish with ; whatever numeric parameter happen to be working on. ; MAJSEP: TST PNTRB ; Parameter B defined ? BGT SEP ; Branch if already defined MOV R0,PNTRB ; Compute length of SUB PNTRB+2,PNTRB ; parameter B MOV R0,PNTRC+2 ; Save current pointer in MCR line INC PNTRC+2 ; and increment it over delimiter MOV R1,PNTRC ; Save # characters left DEC PNTRC ; excluding delimiter ; Continue--end definition of current parameter ; ; Separator character was found, R0 points to separator ; SEP: ADD #4,R2 ; Readjust pointer to next parameter INC R0 ; Skip over separator DEC R1 ; Readjust # characters left BLE DONE ; Branch if nothing left CMP #PNTRA,R2 ; Check if went past parameter 9 BHI SCAN ; Branch if no ; ; Finish up with MCR line, check if enough parameters were found ; and prompt for those that are still needed ; DONE: TST R2 ; Check R2 BEQ 5$ ; If clear, didn't have any parameters SUB #PNTR1,R2 ; Compute offset, R2 points to next parameter ASR R2 ; Divide R2 by 4 to ASR R2 ; compute # parameters encountered 5$: CMP R2,PMIN ; Check for min # parameters BGE ALLDON ; Branch if have min 7$: CMP PMAX,R2 ; Check for Max # BLE ALLDON ; Branch if have max ; ; Prompt for next parameter ; 10$: CALL GETLIN ; Get line from somebody BCC 13$ ; Branch if OK JMP OPNFL ; EOF reached, very bad 13$: MOV FDB+F.URBD+2,R0 ; Fetch start address of line CMPB (R0)+,#QNMRK ; Is the first byte a question mark? BNE 10$ ; No, try again MOVB (R0)+,R3 ; Fetch parameter # to prompt for; 0-9,A-C SUB #60,R3 ; Convert ASCII # to binary # BLT 10$ ; Branch on illegal # CMP R3,#10. ; Check for # < 10 BLT 20$ ; Branch if 0-9 SUB #21,R3 ; Check for A-C BLT 10$ ; Branch if between 9 and A CMP R3,#3 ; Check if # < C BGE 10$ ; Branch if no ADD #10.,R3 ; Set offset relative to parameter 0 20$: ASL R3 ; Adjust R1 for ASL R3 ; offset to correct pointer ADD #PNTR0,R3 ; relative to PNTR0 TST (R3) ; Check if already defined BGT 10$ ; Branch if yes 25$: MOV NEXTP,R4 ; Define start address in P array MOV R4,2(R3) ; Move it to parameter address pointer MOV FDB+F.NRBD,R1 ; Fetch # bytes in prompt line SUB #2,R1 ; Subtract out "?#" prefix MOV #INBF,R5 ; Going to copy the prompt in place 28$: MOVB (R0)+,(R5)+ ; Very important for internal files (I SOB R1,28$ ; unwittingly found out) MOVB #QNMRK,(R5)+ ; Insert ? MOVB #SPA,(R5) ; Insert space MOV #INBF,R0 ; Fetch new start address for prompt MOV FDB+F.NRBD,R1 ; Fetch prompt line length again ; ; At this point, registers contain: ; R0 = points to start of prompt ; R1 = length of prompt ; R2 = # parameters currently defined ; R3 = points to parameter pointer being defined by prompt ; R4 = points to start address for read after prompt ; 30$: QIOW$S #IO.RPR,#2,#1,,#IOSTS,, ; Issue prompt CMPB IOSTS,#IS.SUC ; Check QIO error status BNE 40$ ; Branch on error CMP IOSTS,#IS.CR ; Check for return BNE 40$ ; Branch if not termination MOV IOSTS+2,R0 ; Fetch byte count for parameter just read in MOV R0,(R3) ; Set parameter byte count ADD R0,NEXTP ; Define next available spot in P array INC R2 ; Show that another parameter has been defined BR 7$ ; Branch to see if done, or prompt again ; ; Something went wrong on read after prompt, set severe exit ; status and leave. ; 40$: JMP ERROR ; ; We have all necessary parameters, start building command lines. ; ALLDON: .IFDF $DBG2 ; ;JGD06 ;**** debug section, output all parameters in order ;PRS MOV #PNTR0,R2 ; ADDRESS OF FIRST PARAMETER ;PRS 1$: MOV (R2)+,R0 ; FETCH PARAMTER LENGTH ;PRS MOV (R2)+,R1 ; AND START ADDRESS ;PRS TST R0 ; ANYTHING THERE ;PRS BLE 2$ ; SKIP WRITE ;PRS QIOW$S #IO.WLB!TF.WAL,#2,#1,,,, ;PRS 2$: CMP #PNTRC,R2 ; DONE? ;PRS BHIS 1$ ;PRS EXST$S ;PRS ;**** END DEBUG SECTION ;PRS .ENDC ;$DBG2 ;JGD06 ; ; Register usage for regeneration of command lines: ; R0 = pointer to new command line being created ; R1 = # bytes left available in new command line ; R2 = pointer to command line template ; R3 = # bytes remaining to check in template ; NEXT: ; Reentry point for multiple line commands MOV #CMD,R0 ; Fetch start address for command being made MOV #79.,R1 ; Define max. length for command CLR LINTYP ; Clear both SAVTYP (leading character of CCL ; file line is * or +), and MORE (flag for ; continuation line, + line terminator) CLR NOSTOP ; Clear flag that would exit right after spawn CONTIN: ; Reentry point if next line is cotinuation of ; previous line (previous line ended with +) CALL GETLIN ; Get a line from somebody BCC 5$ ; Branch if OK JMP OPNFL ; Exit on I/O error 5$: MOV FDB+F.URBD+2,R2 ; Fetch start address for command template MOV FDB+F.NRBD,R3 ; and template's length .IFDF $DBG3 ; ;JGD06 ;**** DEBUG SECTION -- ; PRS QIOW$S #IO.WAL,#2,#1,,,, ; SPIT OUT TEMPLATE LINE;PRS ;**** END DEBUG SECTION ;PRS .ENDC ; ;JGD06 TSTB MORE ; Continuation from previous line? BNE 35$ ; Branch if yes, start matching immediately 10$: CMPB (R2),#MINUS ; Is line a "Wait for task exit" line? BEQ 30$ ; Branch if yes 20$: CMPB (R2),#PLUS ; Is template line a multiple line specifier? BEQ 30$ ; Branch if yes CMPB (R2),#STAR ; Is it last template line to fetch from file? BNE NEXT ; Branch if no, unknown line type 30$: MOVB (R2)+,SAVTYP ; Save template line type DEC R3 ; Readjust byte counter for template line 35$: CMPB (R2),#PCNT ; Hit special character? BNE 40$ ; Branch if no .IFDF $DBG4 ; ;JGD06 ;**** DEBUG SECTION -- ; ;PRS MOV FDB+F.URBD+2,R4 ; SET START ADDRESS ;PRS MOV FDB+F.NRBD,R5 ; FETCH TOTAL LINE LENGTH ;PRS SUB R3,R5 ; GET # BYTES DONE ;PRS QIOW$S #IO.WAL,#2,#1,,,, ; SHOW WHATS DONE IN TEMPLATE;PRS MOV #CMD,R4 ; FETCH START ADDRESS OF COMMAND ;PRS MOV #79.,R5 ; AND TOTAL # BYTES ALLOWED ;PRS SUB R1,R5 ; DETERMINE # VALID BYTES IN COMMAND ;PRS QIOW$S #IO.WAL,#2,#1,,,, ; SHOW WHATS GOING INTO COMMAND;PRS ;**** END DEBUG SECTION ;PRS .ENDC ; ;JGD06 CALL FIXUP ; Let fixup replace special characters BCS TOOLNG ; Branch if FIXUP hit a snag TST R3 ; Check status of # bytes left in template BGT 35$ ; Branch if still something there BR 45$ ; Else, get out 40$: MOVB (R2)+,(R0)+ ; Copy over directly to new command line DEC R1 ; Readjust # bytes available in command BLT TOOLNG ; Branch if command got too long DEC R3 ; Readjust # bytes in command template BGT 35$ ; Branch if still stuff in template 45$: CMPB -1(R2),#PLUS ; Was last character in template a "+" BNE TOMCR ; Branch if no, command ready for MCR... INC R1 ; Template line continuing to next line of file DEC R0 ; readjust command line pointer and byte count COMB MORE ; Set flag for continuation BR CONTIN ; Branch to fetch next line from file TOMCR: MOV R0,R1 ; Copy current pointer position MOV #CMD,R0 ; Fetch start address of command SUB R0,R1 ; and compute byte count MOV NOSTOP,R2 ; Set R2 to value of NOSTOP, non-zero on ; %$% template line terminator for immediate ; exit after spawn. .IFDF $DBG5 ; ;JGD06 ;**** DEBUG SECTION -- ; ;PRS QIOW$S #IO.WAL,#2,#1,,,, ; SEND IT TO TI: INSTEAD OF MCR CMPB SAVTYP,#STAR ; ;PRS BEQ 99$ ; ;PRS JMP NEXT ; ;PRS 99$: BR EXIT ; WHO KNOWS WHAT TROUBLE I'M IN ;PRS ;**** END DEBUG SECTION ; ;PRS .ENDC ; ;JGD06 CMPB SAVTYP,#MINUS ; Was the line a "wait for task exit" line BNE 10$ ; Branch if no CALL WAITCK ; Send command to WAITCK to connect to task BCS TYPERR ; Send out message on error-WAITCK sets up R0 JMP NEXT ; Else, task exitted, continue with next line 10$: TST QTFLAG ; Was %Q seen ;JGD06 BEQ 15$ ; If EQ, no ;JGD06 TST QUIT ; Was a required parameter defaulted ;JGD06 BNE ENDDUP ; If NE, yes, don't send MCR a command ;JGD06 15$: TST DBGFLG ; Was debug (%D) found ;JGD07 BEQ 20$ ; If EQ, no ;JGD07 MOV #MSG7,R0 ; Asume is %D (debug) ;JGD05 CALL TYPEIT ; And tell user it was encountered ;JGD05 CLR DBGFLG ; Reset DEBUG flag ;JGD05 BR 30$ ; Now print out expanded command ;JGD05 20$: TST PRINT ; Was print flag seen (%P) ;JGD07 BEQ 40$ ; If EQ, no ;JGD07 CLR PRINT ; Reset PRINT flag ;JGD07 30$: ;CLRB CMD+116 ; Write out command causing trouble ;JGD05 MOV #CMD,R0 ; Get address ;JGD05 ADD R1,R0 ; Point to last char in command ;JGD05 MOVB #15,(R0)+ ; Tack on a ;JGD05 MOVB #12,(R0)+ ; And a ;JGD05 CLRB (R0) ; Set a null to stop printout ;JGD05 MOV #CMD,R0 ; Write out the truncated command ;JGD05 CALL TYPEIT ; Tell the user the news ;JGD05 MOV #EX$SUC,R0 ; Show successful exit status ;JGD05 BR ENDDUP ; More lines to process? ;JGD05 40$: CALL PUTMCR ; Spawn to MCR BCC ENDDUP ; No, errors, is this last line? MOV #MSG6,R0 ; Error, warn user SPAWN failed BR TYPERR ; Exit with error ENDDUP: CLR NOSTOP ; Reset this in case needed nexT time ;JGD03 CMP #EX$SUC,R0 ; Is it success ;JGD03 BNE ERROR ; If NE, Error - Bad status ;JGD03 CMPB SAVTYP,#'* ; Is this the final command? ;JGD03 BEQ FINISH ; Branch if done JMP NEXT ; Not done yet, branch for next line FINISH: MOV R0,EXSTAT ; Done, save exit status from spawn BR EXIT ; And exit TOOLNG: MOV R0,EXSTAT ; Save exit status TST PRINT ; Should we just PRINT line to TI: ;JGD07 BNE 15$ ; If NE, yes ;JGD07 MOV #MSG7,R0 ; Asume is %D (debug) ;JGD05 TST DBGFLG ; Is it? ;JGD05 BNE 10$ ; If NE, yes ;JGD05 MOV #MSG5,R0 ; Else, say line is too long ;JGD05 10$: CALL TYPEIT ; Type on TI: 15$: CLRB CMD+116 ; Write out command causing trouble MOV #CMD,R0 ; Write out the truncated command TYPERR: CALL TYPEIT ; Tell the user the bad news ERROR: MOV #EX$SEV,EXSTAT ; Set up severe error status EXIT: CALL CLOS ; Close .CCL file TST CLIFLG ; Are we a CLI ;JGD09 BEQ 5$ ; No, just exit, at last ;JGD09 JMP CLI ; Back for another cmd ;JGD09 5$: TST RING ; Should we ring terminal bell on exit ;JGD04 BEQ 10$ ; If EQ, no ;JGD04 MOV #BELMSG,R0 ; Set to ring terminal bell ;JGD04 CALL TYPEIT ; And send it to TI: ;JGD04 10$: EXST$S EXSTAT ; Exit with status EXIT$S ; If exit with status fails, just exit ; ; Error message typer, error text ends in null ; TYPEIT: MOV R1,-(SP) MOV R0,R1 1$: TSTB (R1)+ BNE 1$ DEC R1 SUB R0,R1 QIOW$S #IO.WLB!TF.WAL,#2,#1,,,, MOV (SP)+,R1 RETURN ; ; Close our 1 file ; CLOS: TSTB FDB+F.LUN ; Check unit #, if 0, doing internal "file" BEQ 5$ ; skip close if internal "file" CLOSE$ #FDB 5$: RETURN ; ; Open a file on LUN 1, dataset descriptor in R1, error label in R2. ; Also, define (redefine) input buffer and size (#INBF,80.). ; OPEN: OPEN$R #FDB,#1,R1,,#INBF,80. BCC 1$ JMP @R2 1$: RETURN ; ; Print could not access system file & die ; OPNFL: MOV #MSG2,R0 JMP TYPERR ; Exit with severe error ;+ ; WAITCK -- Wait for task to exit ; This subroutine processes the CCL command "-TASKNAME". ; On entry, R0 points to start of taskname, R1 set to # bytes in ; taskname. R0-R3 are expendable. ;- WAITCK: CLR CNCT+C.NCTN+2 ; Clear out old task name CLR CNCT+C.NCTN ; Clear out old task name MOV #TSKNAM,R2 ; Get address of where to shove task name MOV #6,R3 ; Repeat 6 TIMES 1$: MOVB (R0)+,(R2)+ ; Move byte to task name DEC R3 ; Readjust # to move BLE 5$ ; branch if finished with 6 SOB R1,1$ ; Readjust # left in template line ; Branch if still stuff there 2$: MOVB #SPA,(R2)+ ; Space fill taskname if necessary SOB R3,2$ ; Readjust # to move ; Do it to remaining characters 5$: MOV #TSKNAM,R0 ; Recover start address of taskname MOV #1,R1 ; Accept a . in task name CALL $CAT5 BCC 10$ ; If CC, conversion complete(all three char) MOV R1,CNCT+C.NCTN ; QIO: QIOW$ IO.WVB,LUN2,EF2,,ISB,, SPWN: SPWN$ MCR...,,,,,1 ; ; Error messages ; EMM2: .ASCII /CCL -- Task not in system/ EMM2L=.-EMM2 EMM3: .ASCII /CCL -- Syntax error/ EMM3L=.-EMM3 .IFDF $PIP EMM4: .ASCII /CCL -- Command parsing error after PIP:/ EMM4L=.-EMM4 .ENDC .EVEN ; ; ADD SOME MISCELLANEOUS DEFINITIONS HERE--FORMERLY IN CCL'S ; $VARS .PSECT -- PRS 3/81 ; CMDNAM: .WORD 0 NOBYTE: .WORD 0 ; ; List of valid DCL commands. Those entries that can also take ; a prefix of "NO" are indicated by "-1" in the table and must ; immediately follow the un-prefixed entry for the same command. ; ; Normally commands conditionalized with $PIP or $DCLX will not get ; assembled but will be handled by the internal table. ; CMDTBL:; .if df $PIP ; Do we want this subset? .RAD50 /DIR/ ; LIst directory on TI: .RAD50 /PUR/ ; Purge directory .RAD50 /SPO/ ; Spool files via PIP /SP .RAD50 /FRE/ ; Display number of free blocks .RAD50 /DEL/ ; Delete file(s) .RAD50 /TYP/ ; Type file(s) on ti: .RAD50 /LIS/ ; .RAD50 /CRE/ ; Create a file .RAD50 /TRU/ ; Truncate file(s) .RAD50 /SOR/ ; Sort/brief listing .endc; $PIP ; .RAD50 /CHD/ ; Change default directory .RAD50 /UIC/ ; " " " .IFDF $DCLX ; .RAD50 /ATS/ ; List active tasks .RAD50 /SHQ/ ; Show print and batch queues in full format .RAD50 /SHW/ ; Show print and batch queues in short format .RAD50 /DLG/ ; Display terminals on TI: .RAD50 /POO/ ; Display the current amount of pool .RAD50 /SYS/ ; Display current system UIC .ENDC ;$DCLX .RAD50 /DLY/ ; Delay .RAD50 /HEY/ ; Notify terminal of specified task exit .IFDF $DCLX ; .RAD50 /BEL/ ; Ring terminal bell .RAD50 /PAG/ ; Erase terminal screen of VT100/TEK 4014 .RAD50 /ERA/ ; Erase terminal screen of VT52 .RAD50 /SCR/ ; Set VT100 to scroll mode .WORD -1 ; Set VT100 to noscroll mode .RAD50 /HOL/ ; SET /HOLD=TI: .WORD -1 ; SET /NOHOLD=TI: .ENDC ;$DCLX ; ENDCMD: ; End of command table ; ; Co-table to CMDTBL that contains the address the the servicing routine ; for the decoded command. ; JMPTBL: ; .if df $PIP ; .WORD PIP ; Directory listing .WORD PIP ; Use also for PURGE .WORD PIP ; Use also for SPOOL .WORD PIP ; Use also for FREE .WORD PIP ; Use also for DELETE entry .WORD PIP ; Use for TYPE .WORD PIP ; Use for LIST .WORD PIP ; Use PIP for CREATE .WORD PIP ; Use PIP for TRUNCATE .WORD SRD ; Use code template for SRD /LI .endc; $PIP ; .WORD CHD ; .WORD CHD ; .IFDF $DCLX ; .WORD ATS ; .WORD SHQ ; .WORD SHW ; .WORD DLG ; Show actice terminals .WORD POO ; Show pool .WORD SYS ; Display SYSUIC .ENDC .WORD DLY ; Delay for just a moment .WORD HEY ; Connect to task .IFDF $DCLX ; .WORD BELEP ; Ring terminal bell .WORD PAGE ; Erase VT100 screen .WORD ERASE ; Erase VT52 screen .WORD SCROLL ; Set VT100 to scroll mode .WORD NSCROLL ; Set VT100 to normal mode .WORD HOLD ; SET /HOLD =TI: .WORD NOHOLD ; SET /NOHOLD=TI: .ENDC ; $DCLX NOPRE: .BYTE 0 ; 1 if "NO" prefixes command MCRBUF: .BLKB 40. ; Buffer to build command line .BLKB 8. ; (******) .EVEN .PAGE .SBTTL Compress Command Line ; ; Get the command line from MCR and peel off the command from it. ; The command is defined as the first N characters of the line up to ; but not including the first non-alphanumeric ; DCL: ; REF label TST CLIFLG ; Are we a CLI ;JGD09 BEQ 1$ ; If EQ, no, continue ;JGD09 RETURN ; If a CLI, HEY or DLY would hang CLI ;JGD09 ; So return and let catchall get them ;JGD09 1$: ;JGD09 MOV #MCRBUF,SPWN+S.PWCA ; Set buffer address in normal SPWN DPB MOV #EXSTAT,SPWN+S.PWES ; and EXIT status block address MOV #MCR,R0 ; Start of MCR command buffer CLRB NOPRE ; Assume regular command CMPB (R0),#'N ; "NO"? BNE 5$ ; Branch if not CMPB 1(R0),#'O ; BNE 5$ ; Branch if not ADD #2,R0 ; Skip prefix INCB NOPRE ; Signal "NO" seen 5$: CLR R1 ; Control for $CAT5(Do not decode dots) CALL $CAT5 ; Convert R50 to ASCII ; (R1 contains command name) MOV #MCR,R0 ; Get start of command buffer again MOV R0,R2 ; for compression MOV R0,R5 ; Points to rest of command line MOV #CMDTBL,R4 ; Search the command table for a match MOV R1,CMDNAM ; Save command name for later 10$: CMP R1,(R4)+ ; See if it's a match BEQ 20$ ; Go it CMP R4,#ENDCMD ; Are we at end of table? BLO 10$ ; If LO , no, try again 15$: RETURN ; Go and try the .CCL file for a match 20$: TSTB NOPRE ; Prefixed command? BEQ 25$ ; Branch if not CMP (R4),#-1 ; Command takes "NO" prefix? BNE 15$ ; Branch if not, invalid DCL command TST (R4)+ ; Use prefixed command entry 25$: MOV R2,R0 ; Restore R0 ; ; Find where command ends ; The typical command will look as follows: ; ; ; ; The CMDNAME may be more than three characters long, but only the first ; three were tested against the jump table(this is consistent with MCR). ; A space separated the cmd name from any command qualifier string. ; PARSE: CMPB (R0),#SPA ; Is it a space? BEQ REPACK ; If EQ, Yes, go repack buffer CMPB (R0),#ESC ; Is it an ? BEQ REPACK ; If EQ, Yes CMPB (R0),#CR ; Is it a BEQ REPACK ; If EQ, Yes INC R0 ; Else increment counter BR PARSE ; And check next character .PAGE REPACK: MOVB (R0),(R2)+ ; Move in first byte CMPB (R0),#ESC ; Is it BEQ OUT ; If EQ, Yes CMPB (R0),#CR ; Is it BEQ OUT ; If EQ, Yes INC R0 ; Increment counter BR REPACK ; Pack next character OUT: CLRB (R2) ; Leave a null byte to signify end of buffer ; ; At this point the command line appears as follows. ; The command name has been removed from the command buffer. ; Note however, that the first character of the compressed buffer ; may be a space. The line ends with either a or ; depending on which key terminated the read. A zero byte follows this ; in order to simplify checking for EOL ; ; R4 points to the address of command routine +2 ; R5 points to the start of the command buffer ; MOV R4,R0 ; Restore R0 MOV #MCRBUF,R1 ; Get SPAWN buffer TSTB 1(R5) ; Any files follow command? BNE 25$ ; If NE, Yes INC NOBYTE ; Show no data for later 25$: JMP @JMPTBL-CMDTBL-2(R0) ; You can tell this line was BENN'S .enable LSB ERR2: MOV #EMM2,QIOW+Q.IOPL ; Address of error message MOV #EMM2L,QIOW+Q.IOPL+2 ; Length of command BR 10$ ERR3: MOV #EMM3,QIOW+Q.IOPL MOV #EMM3L,QIOW+Q.IOPL+2 BR 10$ .IFDF $PIP ERR4: MOV #EMM4,QIOW+Q.IOPL MOV #EMM4L,Q.IOPL+2 BR 10$ .ENDC 10$: DIR$ #QIOW ; Print error message EXST$S #EX$SEV ; Then comes the bad news .DSABLE LSB .PAGE .if df $PIP ; Only if defined .SBTTL PIP-like commands ; ; DIR,SPOOL,DELETE,TRUNCATE,FREE,PURGE,CREATE, ..etc. all processed here ; SRD: MOV #SORMSG,R0 ; Move in SRD MOV #^RDIR,CMDNAM ; Pretend this is directory command BR COMON ; Branch through common code PIP: CMP CMDNAM,#^RTYP ; Is it TYPE command BEQ 10$ ; If EQ Yes CMP CMDNAM,#^RLIS ; Perhaps LIST? BNE 20$ ; If NE, No 10$: TST NOBYTE ; Any files to list? BNE XIT ; If NE, no files present MOV #TYPMSG,R0 ; Else point to start of command BR COMON ; And skip over 20$: MOV #PIPHD,R0 ; First part of SPAWN command COMON: ; MVZ R0,R1 ; Mov ASCIZ string to SPAWN buffer MVZ R5,R1 ; Mov rest of command up to zero DEC R1 ; Bump off terminating CMP CMDNAM,#^RPUR ; Is it purge? BNE 5$ ; If NE no TST NOBYTE ; Are any files present? BNE XIT ; If NE, no, syntax error MOV #PURMSG,R0 ; Move in second half of line BR DOIT ; 5$: CMP CMDNAM,#^RDIR ; Is it directory? BNE 10$ ; If NE, NO MOV #DIRMSG,R0 ; Mov in second half of name BR DOIT ; 10$: CMP CMDNAM,#^RSPO ; Is it spool? BNE 15$ ; If NE, no TST NOBYTE ; Are any files present? BNE XIT ; If NE, no , syntax error MOV #SPOMSG,R0 ; Move in /SP BR DOIT ; Go do it 15$: CMP CMDNAM,#^RFRE ; Is it /FR command? BNE 20$ ; If NE, no MOV #FREMSG,R0 ; Move in second half of name BR DOIT ; Go issue command 20$: CMP CMDNAM,#^RDEL ; Is it delete? BNE 25$ ; If NE,no TST NOBYTE ; Any files present? BNE XIT ; If NE, no, syntax error MOV #DELMSG,R0 ; Move in second half of command BR DOIT ; Go issue command 25$: CMP CMDNAM,#^RCRE ; Is it create? BNE 30$ ; If NE, no MOV #CREMSG,R0 ; Move in second half of command BR DOIT ; Go issue command 30$: CMP CMDNAM,#^RTRU ; Is it truncate? BNE 35$ ; If NE,no MOV #TRUMSG,R0 ; If YES, move in switch BR DOIT ; And go do it. 35$: CMP CMDNAM,#^RTYP ; Is it type? BEQ DOIT ; If EQ, Yes go do it CMP CMDNAM,#^RLIS ; Perhaps it is LIST? BEQ DOIT ; If YES, do it 40$: JMP ERR4 ; Warn user code fell through here DOIT: MVZ R0,R1 ; Move it in SUB #MCRBUF,R1 ; Length of line to SPAWN CMP R1,#78. ; Is composit line too long? BGT LNGERR ; If GT, Yes MOV R1,SPWN+S.PWCL ; And the length of the command JMP SPWNIT ; SPAWN command and exit XIT: JMP ERR3 ; Say syntax error LNGERR: MOV #EM2,R0 ; It isn't, so say it's too long JMP TYPERR ; Print message and exit with error .endc; $PIP ; No PIP or SRD commands implemented .PAGE .SBTTL CHD ; ; CHD - Change (or show) current UIC ; CHDM1: .ASCIZ \SET /UIC=[\ CHDM2: .ASCIZ \SET /UIC\ .EVEN CHD: ; Ref label TSTB 1(R5) ; Is there a UIC specified? BEQ CHDSHW ; No - show current UIC MOV #CHDM1,R0 ; Get first part of command MVZ R0,R1 ; Move first part of string to spawn buffer MOV R5,R0 ; INC R0 ; 10$: TSTB (R0) ; Is it end of line BEQ 20$ ; If EQ 0, YES, close up command CMPB (R0),#'[ ; Is it "["? BNE 11$ ; If NE, NO, skip MOVB #SPA,(R0)+ ; Yes, make it a space BR 10$ ; And try again 11$: CMPB (R0),#'= ; Is it an "="? BNE 12$ ; If NE, NO MOVB #SPA,(R0)+ ; Yes, make it a space BR 10$ ; And check again 12$: CMPB #'],(R0) ; Is it a "]"? BNE 13$ ; If NE, NO MOVB #CR,(R0)+ ; Yes, so terminate command with CLRB (R0) ; and 0 byte BR 10$ ; And loop again to catch 0 byte 13$: ; If not [, ], = , either number or CMPB (R0)+,#SPA ; If a space seperates the GRM MEM BNE 10$ ; If NE, must be number-get another MOVB #',,-1(R0) ; Else move in a COMMA 20$: MVZ R5,R1 ; Move in UIC DEC R1 ; Bump MOVB #'],(R1)+ ; Close up command SUB #MCRBUF,R1 ; Length of spawn command MOV R1,SPWN+S.PWCL ; Set length in spawn DPB JMP SPWNIT ; Spawn command and exit CHDSHW: ; Ref label MOV #CHDM2,SPWN+S.PWCA ; Set buffer address MOV #8.,SPWN+S.PWCL ; Set buffer length JMP SPWNIT ; Spawn command and exit .IFDF $DCLX .PAGE .SBTTL ATS ; ; ATS - LIST ALL ACTIVE TASKS ( OR ONLY THOSE FOR A TERMINAL) ; ATSM1: .ASCII \ACT /ALL\ ATSM2: .ASCIZ \ACT /TERM=\ .EVEN ATS: TSTB 1(R5) ; US THERE A TERMINAL SPECIFIED BNE ATSTTY ; YES, JUMP MOV #8.,SPWN+S.PWCL ; SET COMMAND LENGTH MOV #ATSM1,SPWN+S.PWCA ; SET BUFFER ADDRESS BR SPWNIT ; SPAWN COMMAND AND EXIT ATSTTY: MOV #ATSM2,R0 ; FIRST PART OF SPAWN COMMAND MVZ R0,R1 ; MOVE ASCIZ STRING INTO SPAWN BUFFER INC R5 ; MVZ R5,R1 ; MOVE IN TERMINAL NUMBER DEC R1 ; BUMP SUB #MCRBUF,R1 ; LENGTH OF LINE TO SPAWN MOV R1,SPWN+S.PWCL ; SET COMMAND LENGTH BR SPWNIT ; SPAWN THE COMMAND .ENDC ; $DCLX .IFDF $DCLX .SBTTL Terminal setting routines .ENABL LC ERAMSG: .ASCII /H/ ; Cursor to (1,1) VT52 .ASCII /J/ ; Erase to end of screen VT52 .BYTE 0 ; Sentinal PAGMSG: .ASCII /[1;1H/ ; Go to (1,1) VT100 .ASCII /[2J/ ; Erase screen VT100 .ASCII <14> ; Erase 4014 screen ; .ASCII /{WOR 0/ ; Erase 4025 .BYTE 0 ; Sentinal .ENDC ;$DCLX ; .IFDF $DCLX ; SCRMSG: .ASCIZ /[?4h/ ; Set terminal to scroll mode NSCMSG: .ASCIZ /[?4l/ ; Set terminal to fast jump mode HOLMSG: .ASCII \SET /HOLD=TI:\ NOHMSG: .ASCII \SET /NOHOLD=TI:\ .EVEN ERASE: MOV #ERAMSG,R0 ; Erase VT52 BR TOTERM ; Branch PAGE: MOV #PAGMSG,R0 ; Get escape string BR TOTERM ; Go write out escape seq SCROLL: MOV #SCRMSG,R0 ; Set up output message BR TOTERM ; Send it out NSCROLL:MOV #NSCMSG,R0 ; Set up output message BR TOTERM ; Send it to terminal BELEP: MOV #BELMSG,R0 ; Write out message TOTERM: CALL TYPEIT ; EXST$S #EX$SUC ; What could possibly go wrong? HOLD: MOV #13.,SPWN+S.PWCL ; Set length MOV #HOLMSG,SPWN+S.PWCA ; And buffer address BR SPWNIT ; Spawn command and wait NOHOLD: MOV #15.,SPWN+S.PWCL ; Set length of command MOV #NOHMSG,SPWN+S.PWCA ; And buffer length BR SPWNIT ; SPawn command and wait .ENDC ;$DCLX ; SPWNIT: DIR$ #SPWN ; Try spawning to MCR... first BCC 10$ ; If CC we got it MOV #BADSPN,R0 ; Print error message CALL TYPEIT ; Out on TI: EXST$S #EX$SEV ; Very bad error 10$: JMP END ; End up .IFDF $DLX .PAGE .SBTTL SHQ - SHW - DLG ; ; SHQ - Show full queue entries ; SHQM: .ASCII \QUE /FU:ALL\ .EVEN SHQ: MOV #11.,SPWN+S.PWCL ; Set length MOV #SHQM,SPWN+S.PWCA ; And buffer address BR SPWNIT ; Spawn command ; ; SHW - Show QUE waiting list ; SHWM: .ASCII \QUE /BR:ALL\ .EVEN SHW: MOV #11.,SPWN+S.PWCL; Set length MOV #SHWM,SPWN+S.PWCA ; And address BR SPWNIT ; Spawn command and exit ; ; DLG - Display logged in terminals ; DLGM: .ASCII \DEV /LOG\ .EVEN DLG: MOV #8.,SPWN+S.PWCL ; Set length MOV #DLGM,SPWN+S.PWCA ; And address BR SPWNIT ; Spawn the command and exit .PAGE ; ; POO - Show pool amount ; POOM: .ASCII \SET /POOL\ .EVEN POO: MOV #9.,SPWN+S.PWCL ; Set length MOV #POOM,SPWN+S.PWCA ; And buffer address BR SPWNIT ; Spawn the command and exit ; ; SYS - Show current system UIC ; SYSM: .ASCII \SET /SYSUIC\ .EVEN SYS: MOV #11.,SPWN+S.PWCL ; Set length MOV #SYSM,SPWN+S.PWCA; And buffer address BR SPWNIT ; Spawn command and exit .ENDC ;$DCLX .PAGE .SBTTL DLY ; ; DLY NNNU -- Delay 'NNNN' units of time ; DLY: MOV R5,R0 ; Copy buffer pointer CALL $CDTB ; Convert units value MOV R1,R5 ; Save units value BEQ 30$ ; Exit if null MOV #1,R4 ; Assume tics CMPB R2,#'T ; Tics? BEQ 20$ ; Yes INC R4 ; Try next time value CMPB R2,#'S ; Seconds? BEQ 20$ ; If EQ YES INC R4 ; No , assume minutes CMPB R2,#'M ; Minutes? BEQ 20$ ; If EQ, YES INC R4 ; If NE, NO assume hours CMPB R2,#'H ; Hours? BNE 30$ ; If NE, illegal value 20$: MRKT$S #EFN1,R5,R4 ; Issue marktime BCS 30$ ; If directive ERROR JMP END ; Go wait 30$: ; Ref label JMP ERR3 ; Syntax error .PAGE .SBTTL HEY ; ; HEY ; BUFFER: .BLKW 40. EXTBLK: .WORD -1 ; EXIT STATUS BLOCK .BLKW 7 ; ;JGD08 ISB: .WORD 0,0 ; I/O Status block CODES: .WORD E2 .WORD E3 .WORD E4 .WORD FUNNY ; Because exit status is 0,1,2,or 4 .WORD E5 ERRS: .WORD FUNNY ; 0 - Internal consistency error .WORD CMLINE ; 2 - Command line I/O error .WORD SYNTAX ; 4 - Syntax error .WORD TSKCLI ; 6 - Task a CLI .WORD NSTASK ; 8 - No such active task BADSPN: .ASCII /CCL -- Bad SPAWN to ...MCR,/ .ASCIZ / Save printout and get help / MESS1: .ASCIZ /HEY -- Task / MESS2: .ASCIZ / exited with status - / ERMES: .ASCIZ /HEY -- / E2: .ASCIZ /warning/ E3: .ASCIZ /success/ E4: .ASCIZ /error/ E5: .ASCIZ /severe error/ NSTASK: .ASCIZ /Task not active/ TSKCLI: .ASCIZ /Bad task/ SYNTAX: .ASCIZ /Invalid syntax/ CMLINE: .ASCIZ /Bad command line/ FUNNY: .ASCIZ /FUNNY -- Internal consistency error/ .EVEN HEY: MOV #CNNECT+C.NCTN,R3 ; Get address to put taskname MOV R5,R0 ; Copy buffer pointer CLR R5 ; Zero error indicator CMPB (R0),#SPA ; Space? BNE 20$ ; If NE, NO TSTB (R0)+ ; Yes, skip over it 20$: ; Ref label CALL $CAT5 ; Convert ASCII takname to RAD50 BCS 30$ ; If CS less than 3 characters in taskname MOV R1,(R3)+ ; 1st part of taskname in connect DPB CALL $CAT5 ; Convert more taskname into RAD50 BCS 40$ ; If CS terminating character in R2 30$: ; MOVB (R0),R2 ; Get terminating character 40$: ; MOV R1,(R3) ; Taskname in connect DPB CMPB R2,#ESC ; Escape? BEQ 50$ ; If EQ YES, OK CMPB R2,#CR ; Carriage return? BNE ERROR2 ; If NE invalid terminator .PAGE .SBTTL Connect and Wait DIR$ #CNNECT ; Connect to the specified task CMP $DSW,#IS.SUC ; Successful connection? BEQ 50$ ; If EQ, YES CMP $DSW,#IE.INS ; Was specified task A CLI? BEQ ERROR3 ; If EQ YES CMP $DSW,#IE.ACT ; Was task inactive? BEQ ERROR4 ; If EQ, YES BR ERROR0 ; No funny error 50$: ; STSE$S #EF1 ; Wait for connected task to EXIT MOV #BUFFER,R0 ; Get output buffer address MOVB #BELL,(R0)+ ; Put in a BELL MOV #MESS1,R1 ; Get address of 1st part of MESSAGE CALL MOVE ; Put it in output buffer MOV CNNECT+C.NCTN,R1 ; Get 1st part of taskname CALL $C5TA ; Convert taskname to RAD50 MOV CNNECT+C.NCTN+2,R1 ; Get 2nd part of taskname CALL $C5TA ; Convert second part of taskname MOV #MESS2,R1 ; Get address of 2nd part of message CALL MOVE ; Move it into output buffer MOV EXTBLK,R1 ; Get exit status CMP #5,R1 ; Known return code BHI 60$ ; If HI, YES CLR R2 ; Suppress leading zeroes CALL $CBOMG ; Convert to octal BR 70$ ; 60$: ; ASL R1 ; Get word index MOV CODES(R1),R1 ; Get address of exit code message CALL MOVE ; Move it into buffer 70$: SUB #BUFFER,R0 ; Get length of message MOV R0,QIO+Q.IOPL+2 ; Move length of buffer into QIO DIR$ #QIO ; Print message ENDHEY: EXST$S #EX$SUC ; Exit successfully .PAGE .SBTTL HEY error processing ERROR4: INC R5 ; Task not active ERROR3: INC R5 ; Task a CLI ERROR2: INC R5 ; Invalid syntax ERROR1: INC R5 ; No command line ERROR0: ; Funny internal error ASL R5 ; Get word index MOV #ERMES,R1 ; Get 1st part of error message ;ALI MOV #BUFFER,R0 ; Move to output buffer CALL MOVE ; Move into output buffer MOV ERRS(R5),R1 ; Get address of error message CALL MOVE ; Move message into output buffer SUB #BUFFER,R0 ; Get length of message MOV R0,QIO+Q.IOPL+2 ; Put it in DPB DIR$ #QIO ; Print the error message EXST$S #EX$SEV ; Exit the worst way .PAGE .SBTTL The End ; ; The End ; END: STSE$S #EF1 ; Stop for spawn TST EXSTAT ; If EQ 0, we have success BNE 5$ ; If NE, use what's sent MOV #EX$SUC,EXSTAT ; Show success 5$: EXST$S EXSTAT ; Exit successfully .PAGE .SBTTL Subroutines ;+ ; *** MOVE - Move an ASCIZ string ; ; INPUTS: ; R0 - ADDRESS OF OUTPUT BUFFER ; R1 - ADDRESS OF ASCIZ STRING ; ; OUTPUTS: ; R0 - UPDATED ;- MOVE: ; MOVB (R1)+,(R0)+ ; Move next character TSTB (R1) ; End? BNE MOVE ; If NE NO RETURN ; Return to caller .endc; .END CCL