.MCALL .MODULE .MODULE UCL,VERSION=26,COMMENT=,AUDIT=NO ; Copyright (c) 1998 by Mentec, Inc., Nashua, NH. ; All rights reserved ; ; This software is furnished under a license for use only on a ; single computer system and may be copied only with the ; inclusion of the above copyright notice. This software, or ; any other copies thereof, may not be provided or otherwise ; made available to any other person except for use on such ; system and to one who agrees to these license terms. Title ; to and ownership of the software shall at all times remain ; in Mentec, Inc. ; ; The information in this document is subject to change without ; notice and should not be construed as a commitment by Digital ; Equipment Corporation, or Mentec, Inc. ; ; Digital and Mentec assume no responsibility for the use or ; reliability of its software on equipment which is not supplied ; by Digital or Mentec, and listed in the Software Product ; Description. ; Edit History ; ; 25-FEB-85 George Thissell Jr. ; Allow for possible date rollover ; ; 27-FEB-85 George Thissell Jr. ; Put 177 's in data file to separate ; multiple commands instead of nulls ; ; 28-FEB-85 George Thissell Jr. ; Add patch ..ERR for UCL to UCF change ; ; 18-APR-85 George Thissell Jr. ; Fix bug for replacing commands with ; multiple commands in 1 definition ; ; 22-FEB-90 Bill Gavin ; Use PUSH, POP, RETURN, move blank lines, etc ; No functional changes ; ; 23-FEB-90 Bill Gavin ; No operational changes; Rewrite for clarity, efficiency ; UCL, SEARCH, DEFCMD, INSERT, OFFDEF, SETNUM ; ; 26-FEB-90 Bill Gavin ; Fix display of program version at '*' prompt ; Add allocations OBUF, VERSON, PATLEV ; SHOCMD Add code to display version number ; ; 27-FEB-90 Bill Gavin ; Fix run-on display of cmds and defs ; CHROUT Macro to simplify display in PCMD, PCMO ; SEPSTR String to simplify display in PCMD ; CHKLEN Validate command string length <= SIZ ; PCMD Use CHROUT macro, SEPSTR string, INDENT loop ; PKMO Use CHROUT macro, Terminate string at CMDSIZ ; ; 28-FEB-90 Bill Gavin ; Check command definition length for REPLACE function ; CRECMD Call CHKLEN, GOODLN here to fix REPLAC length bug ; FRMCMD Check string length as well as terminator ; STONEW Move CHKLEN, GOODLN calls to CRECMD (Fix REPLAC length bug) ; ; 9-APR-90 Bill Gavin ; Modify KMON/UCF handshake; Remove BIS of UCF.ON when UCF finishes. ; ; 31-Oct-1990 JFW ; bracket error messages with ;+/;ERROR/.../;- ; ; 11-Jan-91 Bill Gavin ; Fix calculations of UCL.DAT block offsets when ; more than one block of commands is specified. ; ; 17-Jan-91 Bill Gavin ; Fix CMDBKS calculation in SETNUM ; ; 17-Jun-1991 JFW ; fixed .module and added .audit to get UCLTAB info ; ; 27-Jun-1991 Bill Gavin ; Action #????, QAR78.JDW - Rewrite subr PKMO to check for blanks ; before moving chars to OUTBUF, to fix extra blanks when a pair ; of blanks appears at the buffer limit, and gets written out before ; PKMO could back up its pointer. ; ; .SBTTL Overview - Overview of UCL.SAV and UCL.DAT ; ; USER COMMAND LINKAGE ALLOWS THE USER TO DEFINE A COMMAND ; WITH DEFINITION THAT THE USER SPECIFIES. THE COMMANDS ; ARE STORED IN THE FILE SY:UCL.DAT. ; THE USER ENTERS A COMMAND IN THE FORM OF: ; ; DEFINED COMMAND :== DEFINITION ; ; WHERE: ; ; DEFINED COMMAND ; IS THE LOGICAL USER-DEFINED COMMAND ; ; DEFINITION ; IS THE ACTUAL COMMAND TO BE EXECUTED ; ; ; SY:UCL.DAT HAS THE DEFINED COMMANDS IN ITS FIRST BLOCK ; AND THE DEFINITIONS IN THE FOLLOWING EIGHT BLOCKS. ; EACH DEFINED COMMAND HAS A FIXED LENGTH OF 16. BYTES AND ; EACH DEFINITION HAS A FIXED LENGTH OF 128. BYTES. ; THE FOLLOWING IS A PICTURE OF THE FORMAT OF SY:UCL.DAT. ; ;BYTE NUMBER ; 1 16. ;BLOCK 0__________________________________________________________ ;0 | !DEFAULT NUMBER OF COMMNDS IN SY:UCL.DAT | ;16. | DEFINED COMMAND #1. | ;32. | DEFINED COMMAND #2. | ; ; . . ; . . ; . . ; ;496. | DEFINED COMMAND #31. | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -| ;BLOCK 1| DEFINITION OF DEFINED COMMAND #1. | ; | | ; | | ; | | ;128. | DEFINITION OF DEFINED COMMAND #2. | ; | | ; | | ; | | ;256. | DEFINITION OF DEFINED COMMAND #3. | ; | | ; | | ; | | ;384. | DEFINITION OF DEFINED COMMAND #4. | ; | | ; | | ; | | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -| ;BLOCK 2| DEFINITION OF DEFINED COMMAND #5. | ; | | ; . . ; . . ; . . ; ; | | ; - - - - - - - - - - - - - - - - - - - - - - - - - - - - -| ;BLOCK 8. | ;000. | DEFINITION OF DEFINED COMMAND #29. | ; | | ; | | ; | | ;128. | DEFINITION OF DEFINED COMMAND #30. | ; | | ; | | ; | | ;256. | DEFINITION OF DEFINED COMMAND #31. | ; | | ; | | ; | | ;384. | UNUSED AREA | ; | | ; | | ; | | ; ---------------------------------------------------------- .SBTTL UCL - Definitions .ENABL LC .NLIST BEX ;+ ; Define External Macros ;- .MCALL .EXIT, .READW, .WRITW, .LOOKUP, .GTIM .MCALL .CLOSE, .PURGE, .ENTER .SAVESTATUS .REOPEN .MCALL .CSIGEN, .WAIT, .SETTOP, .ASSUME SOB .MCALL .PRINT .GVAL .PEEK .POKE ...CMY ...CMZ .MCALL .AUDIT .AUDIT .UCL, .UCLTAB, .TPMAC ;+ ; Definitions ;- ERRBYT = 52 ;ERROR BYTE FNF = 1 ;FILE NOT FOUND SPC = 1 ;NOT ENOUGH ROOM HRDWRE = 1 ; HARDWARE ERROR CODE CNOPEN = 2 ; CHANNEL NOT OPEN ERROR CODE JSW = 44 ;JOB STATUS WORD CHNIF$ =: 000040 ;BIT 5 SUPER CHAIN BIT OVLY$ =: 001000 ;BIT ? OVERLAY (leave channel 17 open) ;LENCMD = CHAINA ; = 510, Byte count for command LENCMD = 510 ; CHAIN AREA Command Length ;KMOLOC = LENCMD + 2 ; Start of chain buffer at 510 KMOLOC = 512 ; CHAIN AREA ASCII CMD STD.SP = 1000 ; Std Init value for stack pointer KBFLIM = STD.SP - KMOLOC ; Length of the chain area KBFEND = STD.SP - 1 ; Last location in KMON command area $INDDV =: 426 ;Fixed offset pointer to INDDEV CLIFLG =: -2 ;CLI flags UCFON =: 001 ;UCF on DCLON =: 002 ;DCL on CCLON =: 004 ;CCL on UCLON =: 010 ;UCL on UCFKMN =: 200 ;UCF to KMON command passing CLITYP =: -1 ;CLI type UCFRUN =: 000 ;UCF running DCLRUN =: 001 ;DCL running CCLRUN =: 002 ;CCL running UCLRUN =: 003 ;UCL running INDDEV =: 0 ;IND device name CHAN0 = 0 ;CHANNEL ZERO OUTCHN = 12. ;OUTPUT CHANNEL OVYCHN = 17 ;Overlay channel MAXCHN = 10 ; CHANNELS THAT CSIGEN INACTIVATES SIZ = 16. ; SIZE OF ENTRY OF DEFINED COMMAND DSTNUM = 31. ; DISTRIBUTED NUMBER OF COMMANDS CMDPB0 = 31. ; DEFINED COMMANDS IN FIRST BLOCK CMDPBK = 32. ; DEFINED COMMANDS PER BLOCK CMDSIZ = 128. ; MAX. SIZE OF KMON COMMAND DEFPBK = 4 ; NUMBER OF DEFINITIONS PER BLOCK BUFSIZ = 149. ; SIZE OF BUFFER WDSBLK = 256. ; NUMBER OF WORDS PER BLOCK BYTBLK = 512. ; NUMBER OF BYTES PER BLOCK CMDDEF = 9. ; SIZE OF FULL BLOCK OF DEFINED CMDS. ; AND ACCOMPANYING DEFINITIONS HEDLEN = 54. ; LENGTH OF SHOW COMMAND'S HEADER ONE = 1 ; ONE TWO = 2 ; TWO FIVE = 5 ; FIVE SIX = 6 ; SIX TWOBKB = 1024. ; 1024. ; AN ASCII TABLE OF ALL SYMBOLS REFERENCING ASCII CHARACTERS FOLLOWS NULL = 0 ; ASCII NULL SPACE = 40 ; ASCII SPACE XCLAIM = 41 ; ASCII EXCLAIMATION POINT ASTRIX = 52 ; ASCII ASTERIX ZERRO = 60 ; ASCII ZERO SEVVEN = 67 ; ASCII SEVEN COLON = 72 ; ASCII COLON EQUALS = 75 ; ASCII EQUALS SIGN BSLASH = 134 ; ASCII BACKSLASH UPAROW = 136 ; ASCII UP ARROW SMALLA = 141 ; ASCII "a" SMALLZ = 172 ; ASCII "z" ;+ ; Define Local Macros ;- ; CHROUT Move a char to the output buffer, writing the ; buffer out when it is full. .MACRO CHROUT src, ?B MOVB src,(R4)+ ; Move the character CMP MYEND,R4 ; Output buffer full ? BNE B ; No, branch CALL SWRITE ; Write out buffer B: .ENDM CHROUT .PSECT .DATA.,D .DATA. =. .ASECT .=JSW .WORD OVLY$ ; Lie about being overlayed ; so OVLCHN will be open to us .PSECT .CODE.,I .PSECT .DATA. .ASSUME . EQ .DATA. ..CMDS::.WORD DSTNUM ;**PATCH** ; DEFAULT NUMBER OF COMMANDS .ASSUME . EQ .DATA.+2 ..UCLD:: FSPEC: .RAD50 /SY UCL DAT/ ; UCL DATA FILE. EMTARE: .BLKW 10. ; MAXIUM SIZE REQUEST. SAVESP: .WORD 0 ; STACK POINTER SAVE LOCATION. CR:: .ASCII <15> LF:: .ASCII <12> HEAD:: .ASCIZ /! User Command Linkage (UCL)/ .EVEN LIMT:: .LIMIT ; FIND OUT HIGH AND LOW WORD BLKN1 =:LIMT+2 ; HIGH WORD OF PROGRAM APPEND: .BLKB BUFSIZ ; BUFFER FOR CODE TO APPEND. FBUFF: .BLKB BUFSIZ ; BUFFER FOR COMMAND LINE. .EVEN NEWCMD::.BLKB 18. ; STORE NEW COMMAND HERE. LENEW:: .WORD 0 ; LENGTH OF COMMAND ENTERED. LENAMB::.WORD 0 ; LENGTH OF UNAMBIGIOUS PART. LENKMO::.WORD 0 ; LENGTH OF KMON COMMAND. KMOCMD::.BLKB 256. ; STORE KMON EQUIVALENT. .EVEN VARCMD::.BLKB 16. ; COMMAND FOR AMBIGIOUS CASES. ATCLIF: .WORD 0 ; Addr of CLIFLG CLISET: .WORD 0 ; hi byte 0 if running as UCF ; hi byte <> if not running as UCF ; low byte CLIFLG value on entry ; with UCFON and UCFKMN or'ed in. CBLK: .BLKW 5 ; SAVESTATUS/REOPEN block C.SBLK =: 2 ; Starting block number C.LENG =: 4 ; Length in blocks FILTOP: .BLKW 1 ; Original BLKN1 value used to ; calculate file top block for ; SAVESTATUS/REOPEN hack PTR.CH::.WORD 0 ; POINTER TO CHARACTER STRING. DELETE::.WORD 0 ; 0 - NON-DELETE MODE, 1 - DELETE MODE GOODLN::.BYTE 0 ; FLAG FOR GOOD LENGTHS OF COMMANDS .EVEN MYBUFF::.WORD 0 ; OUTPUT BUFFER'S ADDRESS MYBUF2::.WORD 0 ; ADDRESS OF 2nd SPOT OF MYBUFF DEFEXT::.RAD50 / / .RAD50 /COM/ ;DEFAULT OUTPUT FILE EXTENSION .RAD50 / / .RAD50 / / WDCNT:: .WORD 0 ; WORD COUNT OF AMOUNT TO INPUT BLKNUM::.WORD 0 ; CURRENT BLOCK NUMBER MORBKS::.BYTE 0 ; FLAG FOR MORE DEF COMMAND BLOCKS ; =0 NO MORE =1 MORE BLOCKS TO READ CMDBKS::.BYTE 0 ; NUMBER OF DEFINED COMMAND BLOCKS TEMPBF::.BLKB 16. ; TERMPORARY BUFFER TEMPWD::.WORD 0 ; STORES TEMPORARY NUMBER VALUE:: .WORD 0 ; STORES TOTAL NUMBER OF COMMANDS MAXNUM::.WORD 0 ; STORES TOTAL NUMBER OF COMMANDS ODDBKS::.BYTE 0 ; ODD # OF DEFINED COMMAND BLOCKS? ; = 0 YES, = 1 NO CUTOFF::.BYTE 0 ; FLAG FOR SHORTENED READ ; =0 REGULAR READ, =1 SHORTENED READ WWDCNT::.WORD 0 ; WRITE WORDS SIZE OF BUFFER BTOP:: .WORD 0 ; AMOUNT OF BUFFER SPACE IN BYTES TOTBLK::.WORD 0 ; TOTAL NUMBER OF BLOCKS IN BUFFER FSIZE:: .WORD 0 ; SIZE OF UCL.DAT WBLOCK::.WORD 0 ; RELATIVE BLOCK # FOR UCL.DAT DEFADD::.WORD 0 ; ADDRESS OF START OF DEFINTION BLOCKS ; IN MEMORY DEFBLK::.WORD 0 ; BLOCK NUMBER THAT DEFINITIONS START ; AT IN UCL.DAT DEFBKS::.WORD 0 ; NUMBER OF DEFINITION BLCKS IN MEMORY BLKEND::.WORD 0 ; ADDRESS OF END OF BUFFER DECMPR::.WORD 0 ; NUMBER OF BLOCKS OF DEFINED COMMANDS ; IN MEMORY DEFCWD::.WORD 0 ; NUMBER OF WORDS OF DEFINED COMMANDS ; IN MEMORY DEFSCW::.WORD 0 ; NUMBER OF WORDS OF DEFINTIONS IN ; MEMORY MYEND:: .WORD 0 ; SPOT PAST END OF OUTPUT BUFFER SHONUM::.WORD 0 ; BLOCK NUMBER FOR SWRITE SWDCNT::.WORD 256. ; NUMBER OF WORDS FOR SHOW's OUTPUT ; BUFFER NUMPRO::.WORD 0 ; TOTAL NUMBER OF COMMANDS PROCESSED ; BEFORE A MATCH WAS FOUND IN D.B. NOSETB::.BYTE 0 ; SET SPECIAL CHAIN BIT ; = 0 NO, = 1 YES SIGFIG::.BYTE 0 ; SIGNIFICANT FLAG BYTE MCMDS:: .BYTE 0 ; FLAG FOR MULTIPLE COMMANDS ON 1 LINE ; = 0 NO, = 1 YES INIFLG::.BYTE 0 ; FLAG FOR INITIALIZING MODE ; = 0 NO, = 1 YES EXECMD::.BYTE 0 ; FLAG FOR EXECUTING MODE ; = 0 NO, = 1 YES STARFN::.BYTE 0 ; FLAG FOR FINDING A STAR IN DEF. CMD. ; = 0 NO, =1 YES .EVEN EMDMLT::.BYTE BSLASH ; ASCII BACKSLASH .BYTE BSLASH ; ASCII BACKSLASH .EVEN ; " :== " separator string for SHO COMMAND SEPSTR::.BYTE SPACE ; ASCII SPACE .BYTE COLON ; ASCII COLON .BYTE EQUALS ; ASCII EQUALS SIGN .BYTE EQUALS ; ASCII EQUALS SIGN .BYTE SPACE ; ASCII SPACE .BYTE 0 .EVEN CMDCNT::.WORD 0 ; SHOCMD'S COMMAND COUNTER OBUF:: .BLKB 81. ; CSIGEN input line goes here VERSON: .NLCSI PATLEV =: .-2 ;+ ; Messages ;- ..ERR:: ERRUCL: .ASCII /?UCL-/ ; Prefix string. LEVERR: .ASCII /X-/<200> ; Level string. .EVEN ERRARE: .BYTE 0 ; Error code. .BYTE 0 ; ASCII character level. .WORD ERRUCL ; -> to prefix string. .WORD LEVERR ; -> to level byte. .WORD MSGTAB ; -> to start of message table. .WORD 0 ; -> to filename. .WORD FINALE ; -> to abort exit. ;+ ; Message table ;- ;+ ;ERROR MSGLST MSGTAB ERRMSG INV ;level F ERRMSG CHA ;level F ERRMSG INP ;level F ERRMSG OUT ;level F ERRMSG EXS ;level F ERRMSG NRM ;level F ERRMSG FLL ;level F ERRMSG NCA ;level F ERRMSG FIL ;level F ERRMSG LNG ;level F ERRMSG NCM ;level F ERRMSG MEM ;level F ERRMSG IFT ;level F ;- .EVEN MSGEND ; Syslib calling block ; SCOMP ARGBLK: .WORD 3 ARG1: .WORD 0 ARG2: .WORD 0 .WORD FLAG FLAG: .WORD 0 ;STORE RESULT OF CMP STRINGS KMOCAS: .BLKB 256. ; STORE CASE CONVERSION FOR KMOCMD ARG1CA: .BLKB SIZ ; STORE CASE CONVERSION FOR ARG1 ARG2CA: .BLKB SIZ ; STORE CASE CONVERSION FOR ARG2 KMONPT: .BYTE 0 ; 0 - DOING NEWCMD 1 - DOING KMOCMD PARBIT: .BYTE 0 ; FLAG FOR COMING FROM PARSE:: .EVEN .SBTTL UCL, RESTAT Main code ;+ ; Main - The main code of UCL, all the routines are called from ; this point. There are three modes of operation for UCL, 1) The ; user is defining a command; 2) The user is executing a defined ; command; 3) The user is running UCL to get a list of ; the commands that have been defined. After obtaining the user-defined ; line from the chain area it is determined if the user ; is defining or executing a command. The appropriate routines ; are then called. When defining a command UCL.DAT is searched to ; see if the command already exists. ; If it does not exist then it is stored as a new command, ; provided there is room in the data base. ; If the user is executing a command the data base is searched ; for the command and the command is prepared to be sent to KMON. ; If the user wants to list the commands, then the appropriate ; routines are called to display the commands in UCL.DAT ; ; This routine affects the contents of : R0 ;- .PSECT .CODE .ENABL LSB UCL:: NOP ; Place for BPT for DEBUG ...CMZ MOV SP,SAVESP ; Save stack pointer .GTIM #EMTARE,#EMTARE ; Check possible date rollover MOV BLKN1,FILTOP ; Save original BLKN1 value CALL CHKUCF ; Running as UCF? RESTAT:: MOV SAVESP,SP ; Restore the stack pointer CALL CLEAN ; Go clean stuff CALL GETLIN ; Go get line BCS FINALE ; Branch if SHOW COMMANDS CALL CHKTYP ; Are we defining a command? BCS 10$ ; NO, Branch for execution ; Define/replace a command CALL PARSE ; Parse command line CALL CRECMD ; Go enter command BR FINALE ; Go exit ; Execute an existing command 10$: CALL REOPEN ; Open UCL.DAT file CALL GETCMD ; Move command to chain area CALL SEARCH ; Search data base for command BCS 120$ ; Didn't find it, try KMON MOV NUMPRO,R4 ; R4 = d. c. already processed ADD R4,R2 ; R2 = total d. c. processed CALL FRMCMD ; Form command from definition INCB NOSETB ; Don't set special chain bit FINALE: .CLOSE #CHAN0 ; Close channel 0 .PURGE #OUTCHN ; Purge channel 12. TSTB NOSETB ; Set special chain bit ? BEQ 160$ ; No, branch BR 130$ ; Yes, pass it to KMON ; Didn't find command, try KMON 120$: TSTB CLISET+1 ; Didn't find it, are we UCF ? BNE 140$ ; No, report cmd not found ; Pass the command to KMON for execution 130$: .POKE #EMTARE,ATCLIF,CLISET ; Indicate passing cmd to KMON BIS #CHNIF$,@#JSW ; indicate in JSW, too BR 160$ ; Just return ;+ ;ERROR 140$: .ERR #ERRARE,#EXS,LEVEL=F,RETURN=YES ; ;- .PURGE #OUTCHN ; Close open channel 160$: CLR R0 ; CLR R0 for .EXIT .EXIT ; Exit to KMON... .DSABL LSB .SBTTL CHKUCF - Test for operation under UCF ;+ ; CHKUCF -Set the UCFON bit in CLIFLG if c(CLITYP) = UCFRUN. ; Save addr of CLIFLG in ATCLIF, ; Also set UCFKMN in CLISET if so. ; ; Destroys R0 and R1 ;- CHKUCF:: .GVAL #EMTARE,#$INDDV ; Get addr of INDDEV ; BCS ? ; Ignore error ADD #CLIFLG-INDDEV,R0 ; Get addr of CLIFLG/TYP MOV R0,R1 ; Save this addr MOV R1,ATCLIF ; and in memory .PEEK #EMTARE,R1 ; Get CLIFLG/TYP ; BCS ? ; Ignore error MOV R0,CLISET ; save old value BIT #177400,R0 ; check the CLITYP .ASSUME UCFRUN EQ 0 BNE 10$ ; Not running as UCF PUSH R0 ; Save value MOV R0,CLISET ; Use old value and BIS #UCFKMN,CLISET ; Set UCFKMN bit in CLISET .POKE #EMTARE,R1,(SP)+ ; and "BIS" it back ; BCS ? ; Ignore error 10$: ...CMY RETURN .DSABL LSB .SBTTL PARSE - Use .TPARS to parse define command line ;+ ; PARSE - .TPARS is a table driven parser available for RT-11 programs. ; A given syntax is defined for the valid command line and a ; state table is contructed. IF the command does not follow any ; of the defined states then the carry is returned set to ; the user program. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine will set up the following: ; ; R1 = Option word ; R2 -> Keyword table ; R3 = Length of string to be parsed ; R4 -> String to be parsed ; R5 -> Label in state table (starting state). ; ; This routine affects the contents of : R1 -> R5 ;- .ENABL LSB PARSE:: MOV #FBUFF,R5 ; R5-> STRING TO CONVERT MOV #ARG1CA,R4 ; R4-> STRING TO HOLD FLAGS MOV #SIZ,R3 ; R3=SIZE BISB #ONE,PARBIT ; SET FLAG FROM PARSE CALL CAPIT ; GO CAPITALIZE FBUFF BICB #ONE,PARBIT ; CLEAR FLAG ; COME BACK WITH ARG1CA AND KMOCAS FLAGS SET FOR CHARS CONVERTED. ; WANT TO RESET THESE CHARS AFTER TPARS CLR R1 ; Ignore blanks MOV #UCLKTB,R2 ; R2 -> keyword table MOV LENCMD,R3 ; Length of string MOV #FBUFF,R4 ; R4 -> string address MOV #START,R5 ; R5 -> start of table CALL .TPARS ; Call TPARS BCS 10$ ; Branch if error ; TIME TO UNCAPITALIZE THE CHARS WE CONVERTED. MOV #NEWCMD,R5 ; R5-> STRING TO UNCAP MOV #ARG1CA,R4 ; R4-> STRING WITH FLAGS MOV #SIZ,R3 ; R3=SIZE CALL UNCAP ; GO UNCAP CHARS MOV #KMOCMD,R5 ; R5-> STRING TO UNCAP MOV #KMOCAS,R4 ; R4-> STRING WITH FLAGS MOV #CMDSIZ,R3 ; R3=SIZE CALL UNCAP ; GO UNCAP CHARS RETURN ; Return to caller ;+ ;ERROR 10$: .ERR #ERRARE,#INV,LEVEL=F,RETURN=N ; ;- .DSABL LSB .SBTTL CAPIT - Capitalize string .ENABL LSB ; This routine expects the following to have been setup before ; entering this routine: ; R5 -> string to capitalize ; R4 -> string to hold flags ; R3 = size of string to capitalize CAPIT:: 40$: TSTB (R5) ; POINTING AT NULL ? BEQ 80$ ; YES, BRANCH TSTB PARBIT ; COMING FROM PARSE ? BEQ 41$ ; NO, SKIP COLON CHECK CMPB (R5),#COLON ; COLON FOUND ? BEQ 60$ ; YES, BRANCH 41$: CMPB (R5),#SPACE ; SPACE FOUND ? BEQ 70$ ; YES, BRANCH ; IF WE HIT HERE WE KNOW THAT WE'VE HIT A CHARACTER. CHECK IT TO SEE ; IF WE SHOULD CONVERT TO UPPER CASE AND SET FLAG IF WE DO CLRB (R4) ; CLEAR OUT FLAG CMPB #SMALLA,(R5) ; BETWEEN a AND z ? BHI 50$ ; NO, BRANCH CMPB #SMALLZ,(R5) ; BETWEEN a AND z ? BLO 50$ ; NO, BRANCH ; HIT HERE KNOW THAT I HAVE A CHAR TO CONVERT TO UPPER CASE. ; SO CLEAR THE BIT AND SET THE FLAG INDICATING CASE CONVERSION BICB #SPACE,(R5) ; CLEAR BIT MOVB #1,(R4) ; SET FLAG ; NOW JUST ADJUST POINTERS AND GO GET NEXT CHAR 50$: CMPB (R5)+,(R4)+ ; MOVE UP 2 POINTERS SOB R3,40$ ; GO LOOP IF NOT DONE 60$: ; HIT HERE KNOW FOUND A COLON. IF FIRST COLON FOUND THEN THE "==" ; SHOULD BE NEXT CHARS. (IF NOT DONT WORRY, TPARS WILL FLAG IT) ; HAVE R4 -> KMOCAS AND SKIP THE ":==" TSTB KMONPT ; FIRST COLON ? BNE 50$ ; NO, JUST A CHAR MOVB #ONE,KMONPT ; SET FLAG FOR FIRST COLON TSTB (R5)+ ; SKIP PAST ":" CMPB (R5)+,(R5)+ ; SKIP PAST "==" MOV #KMOCAS,R4 ; R5 -> CASE FLAGS FOR KMOCMD SOB R3,40$ ; GO LOOP IF NOT DONE ; NOTE: NOT SURE IF THIS STOP ON KMOCMD. MIGHT NEED A CHAR COUNTER FOR LOOP 70$: ; HIT HERE FOUND A SPACE. WE WANT TO IGNORE IT WHEN INCREMENTING THE CASE ; POINTER, BUT SKIP PAST IT IN FBUFF. THIS IS BECAUSE ON RETURN FROM ; TPARS, LEADING BLANKS WILL BE GONE. TSTB (R5)+ ; SKIP SPACE SOB R3,40$ ; GO LOOP IF NOT DONE 80$: CLRB KMONPT ; CLEAR FLAG ON EXIT RETURN ; RETURN .DSABL LSB .SBTTL UNCAP - UN-CAPITALIZE BACK TO MIXED CASE .ENABL LSB ; EXPECTS R5 -> STRING TO UNCAP ; R4 -> STRING WITH CASE CONVERSION FLAGS ; R3 = SIZE OF STRING UNCAP:: 10$: CMPB (R5),#SPACE ; IS IT A SPACE ? BNE 20$ ; NO, BRANCH ; IT IS A SPACE. INCREMENT POINTER FOR R5,BUT DON'T FOR R4. ; R4-> A STRING OF FLAGS FOR NON-SPACE CHARS ONLY. TSTB (R5)+ ; SKIP PAST BLANK BR 10$ ; GO CHECK NEXT CHAR 20$: TSTB (R4) ; FLAG TO UNCAP SET ? BEQ 30$ ; NO, BRANCH BISB #SPACE,(R5) ; UNCAP IT 30$: CMPB (R4)+,(R5)+ ; ADJUST POINTERS SOB R3,10$ ; COUNT IT AND LOOP RETURN ; RETURN .DSABL LSB .SBTTL CLEAN - Cleanup performed ;+ ; CLEAN - Scratch locations are cleared, also flag words are initialized. ; Chanel zero used throughout the code is purged. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R5 ;- .ENABL LSB CLEAN:: CLR DELETE ; Clear flag MOV #NEWCMD,R2 ; R2 -> new command MOV #KMOCMD,R3 ; R3 -> KMON MOV #APPEND,R5 ; R5 -> append buffer MOV #BUFSIZ,R1 ; R1 = size of buffer MOVB #NULL,R4 ; R4 = null .ASSUME NULL EQ 0 10$: CLRB (R2)+ ; Store null CLRB (R3)+ ; Store null CLRB (R5)+ ; Store null SOB R1,10$ ; Branch if not done RETURN .DSABL LSB .SBTTL GETLIN - Get user command line ;+ ; GETLIN - Move the user command line from the chain area to internal buffer ; FBUFF. Calculate the size of the command. In case the user ; did not enter anything ( he is trying to list the commands ; by running UCL ) set the carry and call SHOCMD to display the ; existing commands. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R2 ;- .ENABL LSB GETLIN::MOV #LENCMD,R0 ; R0 -> chain area length CMP (R0),#ONE ; Anything there? BLE 20$ ; No, branch MOV #FBUFF,R1 ; R1 -> buffer to store cmd MOV (R0)+,R2 ; R2 = number of bytes in cmd 10$: MOVB (R0)+,(R1)+ ; Store character SOB R2,10$ ; Branch if not done CLRB @R1 ; Store null CLC ; Clear carry RETURN ; Return 20$: CALL SHOCMD ; Go print command SEC ; Set carry RETURN .DSABL LSB .SBTTL CHKTYP - Check type of UCL command ;+ ; CHKTYP - This routine determines what type of command the user has typed. ; If the user is trying to define a command ( newcommand :== old ) ; then clear the carry. IF the user is trying to execute a command ; set the carry. The syntax to define commands must follow :== . ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 ;- .ENABL LSB CHKTYP::MOV #FBUFF,R1 ; R1 -> buffer for cmd line 10$: TSTB (R1) ; Null? BEQ 30$ ; Yes, branch CMPB #COLON,(R1)+ ; Colon found? BNE 10$ ; No, branch ;+ ; COLON FOUND ON STRING - USER MIGHT BE TRYING TO DEFINE COMMAND. ; CHECK IF "==" FOLLOWS. ;- CMPB #EQUALS,(R1)+ ; Followed '=' ? BNE 30$ ; No, must be a command CMPB #EQUALS,(R1) ; Another equal? BEQ 20$ ; Yes, branch ;+ ;ERROR .ERR #ERRARE,#INV,LEVEL=F,RETURN=N ; ;- 20$: TST (PC)+ ; Clear carry skip next 30$: SEC ; Set carry RETURN .DSABL LSB .SBTTL REOPEN - Open command file ;+ ; REOPEN - This routine opens the existing UCL.DAT ; ; ; This routine is called from: MAIN ; SHOCMD ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 ;- .ENABL LSB REOPEN::CALL LOOK ; Perform lookup BCC 10$ ; Branch if file exist ;+ ;ERROR .ERR #ERRARE,#FIL,LEVEL=F,RETURN=NO,FILE=#FSPEC ; ;- 10$: RETURN ; Return to caller .DSABL LSB .SBTTL GETCMD - Get command from chain area. ;+ ; GETCMD - This routine gets the command from the chain area. ; The user is trying to execute a command. The command is stored ; in buffer NEWCMD and the append text, if any, is stored in APPEND. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R2 ;- .ENABL LSB GETCMD::MOV #KMOLOC,R0 ; R0 -> command location MOV #NEWCMD,R1 ; R1 -> STORE COMMAND HERE MOV #APPEND,R2 ; R2 -> buffer to put extra 10$: MOVB (R0)+,(R1)+ ; Store until a null BEQ 30$ ; Then branch CMPB #SPACE,(R0) ; Is this a blank? BNE 10$ ; No, repeat TSTB (R0)+ ; Skip blank 20$: MOVB (R0)+,(R2)+ ; Store appended command BNE 20$ ; Until CR 30$: RETURN ; Return to caller .DSABL LSB .SBTTL IEREAD - Insert and Execute .READS implemented ;+ ; IEREAD - This routine executes the INSERT and EXECUTE reads. ; OUTCHN is the channel number that performs the read. ; BLKN1 holds the address of the buffer to receive what is read. ; WDCNT is the number of words that will be read in, BLKNUM ; contains the block number of where to begin the read. ; ; This routine is called from: SEARCH ; INIFIL ; INSERT ; SHOCMD ; ; This routine expects the following to already ; have been set up when entered: ; ; OUTCHN = channel number to perform the read ; BLKN1 = address of buffer to receive what is read ; WDCNT = number of words to read in ; BLKNUM = block number of where to begin the read ; ; This routine affects the contents of : R0 -> R1 ;- .ENABL LSB IEREAD::.READW #EMTARE,#OUTCHN,BLKN1,WDCNT,BLKNUM ; Do the read BCC 30$ ; Branch if no error ;+ ;ERROR 20$: .ERR #ERRARE,#INP,LEVEL=F,RETURN=NO,FILE=#FSPEC ; ;- 30$: ADD TOTBLK,BLKNUM ; Count the blocks just read RETURN .DSABL LSB .SBTTL SETNUM Setup number of commands in UCL.DAT ;+ ; SETNUM - This routine sets up the number of commands there are in the data ; base. It also sets up the number of blocks of defined commands ; in UCL.DAT and stores the number. ; ; This routine is called from: SEARCH ; INSERT ; SHOCMD ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R3 ;- .ENABL LSB SETNUM:: ; Copy the byte count ASCII string from first record to TEMPBF MOV BLKN1,R1 ; R1 -> First char (!) MOV #TEMPBF,R2 ; R2 -> Temporary buffer MOV #SIZ,R3 ; R3 = Byte counter 10$: MOVB (R1)+,(R2)+ ; Move 1 char to buffer SOB R3,10$ ; Validate the buffer format MOV #TEMPBF,R2 ; R2 -> Beginning of buffer CMPB (R2)+,#XCLAIM ; First char a "!" ? BNE 130$ ; No, report bad file format ; Convert length from ASCII to binary CLR R3 ; Init command count 20$: CLR R1 ; Clear holding spot MOVB (R2)+,R1 ; Move # to temp word CMPB R1,#SPACE ; Is char a space? BEQ 40$ ; Yes, end of string CMPB R1,#SEVVEN ; Is char at most a 7 ? BHI 140$ ; No, invalid character SUB #ZERRO,R1 ; Make it really a number BMI 140$ ; Err if it was less than ZERRO ASL R3 ; Make room for new number ASL R3 ; Make room for new number ASL R3 ; Make room for new number ADD R1,R3 ; R3 = octal of number BR 20$ ; Go look at next character ; Find out the number of defined command blocks and store in CMDBKS ; The first 'command' is actually the command count, so the first ; block has one fewer commands than the rest. 40$: MOV R3,VALUE ; Save command count TST R3 ; What is the number ? BLE 150$ ; Invalid, must be one or more INC R3 ; Fake - account for cmd count CLR R2 ; Init count 60$: INC R2 ; Count the block SUB #CMDPBK,R3 ; reduce by # of cmds/block BGT 60$ ; More left, keep counting MOVB R2,CMDBKS ; Set count of CMD blocks RETURN ;+ ;ERROR ; File has invalid format, display fatal error message 130$: .ERR #ERRARE,#IFT,LEVEL=F,RETURN=YES,FILE=#FSPEC ; BR 200$ ; Command count has invalid format, display fatal error message 140$: .ERR #ERRARE,#NCM,LEVEL=F,RETURN=YES ; BR 200$ ; Command count is invalid 150$: .ERR #ERRARE,#NCM,LEVEL=F,RETURN=YES ; ;- 200$: .CLOSE #OUTCHN ; Close channel .EXIT .DSABL LSB .SBTTL MOBKS - Determine if there are more defined command blocks ;+ ; MOBKS - This routine determines if there are more defined command blocks ; in UCL.DAT that have yet to be read. ; ; This routine expects the following to already ; have been set up before entering : ; ; BLKNUM = last block # that has was read ; TOTBLK = total # of blocks of UCL.DAT in memory ; ; This routine affects NO registers. ;- .ENABL LSB MOBKS: CLRB MORBKS ; Clear flag for more d.c. CMPB BLKNUM,CMDBKS ; More defined command blocks? BGE 10$ ; No, branch INCB MORBKS ; Set flag for more def. cmds. 10$: RETURN .DSABL LSB .SBTTL DEFCMD Get the number of defined commands in buffer ;+ ; DEFCMD - This routine gets the number of commands that was just read. ; The number will be returned in MAXNUM. ; ; This routine is called from: SEARCH ; INSERT ; SHOCMD ; ; This routine expects the following to already ; have been set up when entered: ; ; MORBKS = Flag for more defined command blocks yet to be read ; BLKNUM = Number of last block that was read ; TOTBLK = Number of total blocks in memory ; VALUE = Maximum number of commands in UCL.DAT ; ; This routine affects the contents of : R0 -> R3 ;- .ENABL LSB DEFCMD:: TSTB MORBKS ; More blocks of def. cmds. ? BNE 70$ ; Yes, branch CMP BLKNUM,TOTBLK ; Was this the first read ? BEQ 88$ ; Yes, we have count in buffer ;+ ; IF THE ROUTINE HITS THIS POINT, THEN THIS IS NOT THE FIRST READ, ; AND THERE ARE NO MORE BLOCKS OF DEFINED COMMANDS. ; THIS MEANS THAT WE COULD HAVE READ IN SOME DEFINITIONS AND WE DO NOT ; WANT TO COUNT THEM AS DEFINED COMMANDS. SO FIRST FIGURE OUT HOW MANY BLOCKS ; OF DEFINITION WE READ IN AND THEN SUBTACT THAT NUMBER FROM THE NUMBER OF ; BLOCKS THAT WE READ IN AND THE RESULT WILL BE THE NUMBER OF BLOCKS ; OF DEFINED COMMANDS THAT WE READ IN. THEN CONVERT THIS NUMBER TO THE ; NUMBER OF DEFINED COMMANDS AND STORE THE RESULT IN MAXNUM. ;- 10$: MOV BLKNUM,R1 ; R1 = # of blocks read in CLR R0 ; Clear high byte MOVB CMDBKS,R0 ; R0 = # of command blocks SUB R0,R1 ; Subtract the # of blocks ; of defined commands ; R1 = # OF BLOCKS OF DEFINITIONS READ IN WITH LAST READ MOV TOTBLK,R2 ; R2 =Total # of buffer blocks SUB R1,R2 ; NOW R2 = # OF BLOCKS OF DEFINED COMMANDS READ IN WITH LAST READ ;+ ; R1 WILL BE THE COUNTER FOR # OF COMMANDS READ IN WITH LAST READ, ; UP UNTIL THE LAST BLOCK. THE USER HAS THE RIGHT TO ONLY ALLOCATE ; A FRACTION OF THE LAST BLOCK FOR DEFINITIONS. THE USER DOES THIS WHEN ; HE PUTS A VALUE IN THE WORD "VALUE" THAT IS NOT A MULTIPLE ; OF THE ORDINARY NUMBER OF COMMANDS PER BLOCK. ; COUNT THE NUMBER OF BLOCKS UP TO THE LAST COMMAND BLOCK THAT WAS READ ; IN WITH THE LAST READ. THE NUMBER OF DEFINED COMMANDS IN THESE BLOCKS ; WILL BE THE NUMBER OF DEFINED COMMAND BLOCKS THAT WAS READ IN WITH THE ; LAST READ MULTIPLIED BY THE NUMBER OF DEFINED COMMANDS PER BLOCK (32.) ;- CLR R1 20$: CMP #ONE,R2 ; Last block of definitions ? BEQ 40$ ; Yes, branch 30$: ADD #CMDPBK,R1 ; Add # of commands per block DEC R2 ; Count block processed BR 20$ ; Go loop ;+ ; NOW ONLY THE LAST BLOCK OF DEFINED COMMANDS IS LEFT TO PROCESS. ; NOW PROCESS THE NUMBER OF COMMANDS THE USER HAS DEFINED MAXIMUM FOR UCL.DAT ; THE DEFINED NUMBER IS IN "VALUE". SUBTRACT THE NUMBER OF DEFINED COMMANDS ; PER BLOCK FROM THIS NUMBER UNTIL THERE IS ONLY AT MOST 1 FULL BLOCK OF ; DEFINED COMMANDS POSSIBLY LEFT. NOW THIS NUMBER IS THE FRACTION OF THE ; LAST BLOCK THAT THE USER WANTED USABLE. IF ITS 32. THEN THE USER WANTED ; A FULL BLOCK OF DEFINED COMMANDS, IF ITS ANYTHING LESS THEN THE USER WANTED ; ONLY A FRACTION OF THE LST BLOCK OF DEFINED COMMANDS USED. ;- 40$: MOV VALUE,R3 ; R3 = Maximum # of def. cmds. 50$: CMP R3,#CMDPBK ; >1 full block of def. cmds.? BLE 60$ ; No, branch SUB #CMDPBK,R3 ; Subt. 1 blk full of def. cmd BR 50$ ;+ ; NOW DOWN TO THE LAST BLOCK OF COMMANDS. ADD THE FRACTION OF THE LAST BLOCK ; THE USER WANTED AVAILABLE FOR DEFINED COMMANDS. ; NOTE: R1 CONTAINS THE # OF DEFINED COMMANDS FOR ALL THE BLOCKS READ IN WITH ; THE LAST READ EXCEPT THE LAST BLOCK. ;- 60$: ADD R3,R1 INC R1 ; Account for the 1ST spot ; of UCL.DAT having !XX ;+ ; R1 NOW CONTAINS THE TOTAL NUMBER OF DEFINED COMMANDS POSSIBLE FROM THE LAST ; READ ;- MOV R1,MAXNUM ; MAXNUM = # of def. commands BR 90$ ; Leave routine ;+ ; IF THE ROUTINE HITS THIS POINT, THEN THERE ARE MORE BLOCKS OF DEFINITIONS ; AND THEREFORE THE READ WAS NOT CUT OFF. ;- 70$: CLR R2 ; R2 = # of defined commands MOV TOTBLK,R1 ; R1 = # of buffer blocks 80$: ADD #CMDPBK,R2 ; Add # of commands per block SOB R1,80$ ; Count all blocks ;+ ; IF THE READ WAS THE FIRST READ THEN WE WANT TO SUBTRACT ONE FROM THE ; NUMBER OF COMMANDS TO ACCOUNT FOR THE FIRST ENTRY IN UCL.DAT WHICH ; CONTAINS DEFAULT INFORMATION AND IS NOT TO BE PROCESSED WITH THE ; REST OF THE DATA BASE. ;- CMP BLKNUM,TOTBLK ; First read ? BNE 85$ ; No, branch DEC R2 ; Account for first entry 85$: MOV R2,MAXNUM ; MAXNUM = # of def. cmds. BR 90$ ;+ ; IF THE ROUTINE HITS THIS POINT, THEN THIS IS THE FIRST READ AND WE HAVE ; READ IN ALL THE DEFINED COMMANDS. THE NUMBER OF DEFINED COMMANDS JUST ; READ IN MUST BE THE NUMBER IN THE FIRST LOCATION OF UCL.DAT., WHICH ; IS STORED IN VALUE. ;- 88$: MOV VALUE,MAXNUM ; Move it BR 90$ ; Leave routine 90$: RETURN .DSABL LSB .SBTTL LOOK - .LOOKUP implemented ;+ ; LOOK - Channel zero is attempted to be opened for file SY:UCL.DAT. If the ; file does not exist the carry is set in return. ; ; If the UCL.DAT file is concatinated to UCL.SAV then no .LOOKUP is ; done, rather the overlay channel is "savestatused", the block offset ; and length are altered and then REOPEN is used to open Channel zero ; as tho a .LOOKUP had occurred (saving lots of directory I/O). ; ; This routine is called from: OPEN ; REOPEN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 ;- .ENABL LSB LOOK:: .SAVESTATUS #EMTARE,#OVYCHN,#CBLK ; Save status of overlay chan BCS 5$ ; failed, do a lookup MOV FILTOP,R0 ; Get last addr in program ADD #511.,R0 ; Round up a block SWAB R0 ; Divide by 256. ASR R0 ; And by 2 for /512. BIC #^C177,R0 ; Strip junk CMP R0,CBLK+C.LENG ; any extra blocks? BGE 5$ ; No, then do the lookup ADD R0,CBLK+C.SBLK ; offset to first data block SUB R0,CBLK+C.LENG ; and shorten it .REOPEN #EMTARE,#OUTCHN,#CBLK ; Now reopen on output chan MOV CBLK+C.LENG,R0 ; R0 = length of file (blocks) BCC 10$ ; Return ok 5$: ; Else try a lookup .LOOKUP #EMTARE,#OUTCHN,#FSPEC ; Open channel BCC 10$ CMPB @#ERRBYT,#FNF ; Is file not found? BEQ 20$ ; Yes, branch ;+ ;ERROR .ERR #ERRARE,#CHA,LEVEL=F,RETURN=NO,FILE=#FSPEC ; ;- 10$: MOV R0,FSIZE ; FSIZE =size of file (blocks) CMP R0,TOTBLK ; Does file fit in buffer ? BLE 12$ ; Yes, use size of file MOV TOTBLK,R0 ; No, use size of buffer 12$: SWAB R0 ; R0 = # of words in file MOV R0,WDCNT ; WDCNT = # of words read TST (PC)+ ; Skip next 20$: SEC ; Set carry RETURN ; Return .DSABL LSB .SBTTL SEARCH Look for command on database. ;+ ; SEARCH - The commands are stored in UCL.DAT. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R4 ;- .ENABL LSB SEARCH:: ; Convert input cmd to upper case to match cmds in database MOV #NEWCMD,ARG1 ; ARG1 -> String to compare MOV ARG1,R5 ; R5 -> AREA TO UNCONVERT MOV #ARG1CA,R4 ; R4 -> STRING TO HOLD FLAGS MOV #SIZ,R3 ; R3 = LENGTH TO DO COMPARES CALL CAPIT ; GO CONVERT TO ALL UPPER CALL DEFSPC ; Go allocate buffers CALL IEREAD ; Go read first two blks CALL SETNUM ; Set up # of cmds. in d.b. CALL MOBKS ; See if more blks of def. cmd CALL DEFCMD ; Set up # of cmds. in memory MOV BLKN1,R1 ; R1 -> buffer MOV #NEWCMD,R3 ; R3 -> Typed-in command ; Find the command in the database 10$: CLR R2 ; R2= Counter for loops 12$: CALL COMPAR ; Go compare commands BCS 30$ ; Branch if equal ADD #SIZ,R1 ; Point to next entry INC R2 ; Increment counter for loops CMP MAXNUM,R2 ; Processed all the commands? BGE 12$ ; No, keep searching ; Read in more of the database TSTB MORBKS ; More blks of def. cmds. ? BEQ 40$ ; No, branch CALL IEREAD ; Go read new blocks CALL MOBKS ; See if more blks of def. cmd CALL DEFCMD ; Set up # of cmds. in memory MOV NUMPRO,R2 ; R2 = # of def. cmds. already ADD R2,R4 ; R4 = total # def. cms. proc. MOV R4,NUMPRO ; NUMPRO = total d.c. processd BR 10$ ; Go loop 30$: TST (PC)+ ; No match, clear carry 40$: SEC ; Match found, set carry RETURN .DSABL LSB .SBTTL FRMCMD - Form Command ;+ ; FRMCMD - The command line is prepared and stored in the chain area. ; The command length also must be stored. ; FRMCMD first gets a pointer to the command to be executed. ; The command is stored in the chain area, if any code is to ; be appended then the terminating null is replaced by a blank ; and the append code attached. In multiple commands a "177" ; separates the different commands. The 177's are translated ; to nulls when forming the commands. ; The string passed to KMON must end on a null. ; ; This routine is called from: SEARCH ; ; This routine expects the following to already ; have been set up when entered: ; ; R2 = Counter for # of commands processed so far, to be used ; to calculate the offset to the proper KMON command ; ; This routine affects the contents of : R0 -> R4 ; Register Usage: ; R0 Count KMON def len, quit at max len CMDSIZ ; R1 Holds char to be output to FORMed command ; R2 Output pointer, R2 -> Output buffer ; R3 Input pointer, R3 -> KMON cmd def ; R4 Insert pointer, R4 -> APPEND text ; ; Delimiter Rules: ; o The command def may terminate with , or at ; the max char count CMDSIZ. ; o Multiple commands are separated in the cmd def ; by <177>s, these go to the output line as s ; o Insertion of APPEND text is indicated by , ; the APPEND text is terminated with a , which ; does not go to the output buffer. ; ; Limits to be checked: ; o Command Length - We shouldn't have to worry about the ; command length, since KMON and the table routine will ; have checked it before this routine is called. ; o Command Definition Length - due to the fixed length ; of the definition table entry, we can't rely on the ; to terminate the definition, we must also ; check for max length. ; o APPEND text - KMON will have processed this text before ; we see it, so we can assume it will end with a ; o FORMed Command length - We must make sure this does not ; overflow the output (CHAIN) buffer. ;- FRMCMD:: ; Locate the definition in the buffer CLRB MCMDS ; Clear multiple commands flag CMP BLKNUM,TOTBLK ; Definition in 1st read ? BNE 5$ ; No, branch DEC R2 ; Account for the !xx in d.b. 5$: MOV R2,R0 ; R0 = # of cmds processed INCB EXECMD ; Set execute flag CALL OFFDEF ; Calculate R3 -> def. ; Move the command definition to the output buffer CLR LENCMD ; Init the command length count MOV #CMDSIZ,R0 ; R0 = Max len of valid command MOV #KMOLOC,R2 ; R2 -> FORMed KMON command 10$: MOVB (R3)+,R1 ; Get char from cmd def CMPB R1,#SPACE ; Is it a space ? BNE 12$ ; No, proceed CMPB #SPACE,(R3) ; Is it two spaces in a row ? BEQ 200$ ; Yes, we're done 12$: CMPB R1,#UPAROW ; Need to INSERT text ? BEQ 50$ ; Yes, insert APPEND text ; Move ordinary char (including and ) to output buffer CALL FRMSTO ; Store char in out buf BCS 200$ ; Buffer full, exit BR 80$ ; Get next char ; Insert APPEND text in place of 50$: MOV #APPEND,R4 ; Set APPEND pointer 52$: MOVB (R4)+,R1 ; Get APPEND char BEQ 80$ ; Found , end of APPEND CALL FRMSTO ; Store char in out buf BCS 200$ ; Buffer full, exit BR 52$ ; Repeat until we find ; Check for end of definition at max length 80$: SOB R0,10$ ; End of command, exit 200$: MOVB #NULL,(R2) ; End command with a INC LENCMD ; Count the RETURN .SBTTL FRMSTO Store character in KMON CHAIN buffer ; Store the character in R1 in the output buffer ; Convert #177 to null, exit with 'C' set if buffer fills, ; leaving room for the terminating null. ; R1 = Character to store ; R2 -> Storage location ; MCMDS = Multiple command flag (Doesn't seem to be used) ; LENCMD= Byte count, kept in 1st word of buffer ; KBFEND= Last storage location in the buffer FRMSTO:: CMPB R1,#177 ; Command separator ? BNE 10$ ; No, proceed MOVB #NULL,R1 ; Yes, change to INCB MCMDS ; Set multiple commands flag 10$: CMP R2,#KBFEND ; Any room in output buffer ? BHIS 100$ ; No, quit, let KMON find error MOVB R1,(R2)+ ; Insert a character INC LENCMD ; Count the char inserted CLC BR 200$ 100$: SEC 200$: RETURN .SBTTL COMPAR - Compare command to existing data base ;+ ; COMPAR - This routine sets up the addresses of the command the user ; typed in and the commands in the data base. It then calls ; CMPSTR to compare the strings. If the command does not match ; the currrent command then the carry is returned clear from ; CMPSTR. ; ; If the command in the data base conatains a "*" then this routine ; also generates all the possible iterations of the command ; trying to find a match. This routine puts the address of the ; command that it generates into ARG2. ; ; Then if there are more iterations of the command the ; user typed in that have not yet been checked, then ; the iteration is formed and CMPSTR is called. ; ; ; This routine is called from: SEARCH ; INSERT ; ; This routine expects the following to already ; have been set up when entered: ; ; R1 -> Defined command in UCL.DAT ; ARG1 -> Command that COMPAR is attempting to find a match for ; ; This routine affects the contents of : R4 ;- .ENABL LSB COMPAR:: PUSH R0 ; Save for later PUSH R1 ; Save for later PUSH R2 ; Save for later PUSH R3 ; Save for later PUSH R5 ; Save for later CLR R3 ; R3 = Unambiguous length MOV R1,R4 ; Save pointer to command 10$: CMPB (R1)+,#ASTRIX ; Is this char a '*'? BEQ 40$ ; Yes, branch INC R3 ; Inc. counter for unambiguous CMP R3,#SIZ ; Processed whole argument? BNE 10$ ; No, branch CLR R3 ; R3 = Counter for characters MOV #VARCMD,R1 ; R1 -> Buffer 20$: MOVB (R4)+,(R1)+ ; Move character to buffer INC R3 ; Counter for chars processed CMP #SIZ,R3 ; Moved all the chars ? BEQ 30$ ; Yes, branch and compare CMPB #SPACE,(R4) ; Is next spot a blank ? BNE 20$ ; No, branch 30$: MOVB #NULL,(R1) ; Terminate string with a null MOV #VARCMD,ARG2 ; ARG2 -> string MOV ARG2,R5 ; R5 -> STRING TO CONVERT MOV #ARG2CA,R4 ; R4 -> STRING TO HOLD FLAGS MOV #SIZ,R3 ; R3= SIZE CALL CAPIT ; GO CAPITALIZE IT CALL CMPSTR ; Go compare strings BCC 90$ ; Branch if not equal BR 99$ ; Branch if equal 40$: CALL CLNVAR ; Clean variable buffer MOV #VARCMD,R1 ; R1 -> Variable command 50$: MOVB (R4)+,(R1)+ ; Store character SOB R3,50$ ; Branch if not done MOV #VARCMD,ARG2 ; ARG2 -> string to compare 60$: ; SET UP THE REGISTERS FOR CONVERTING ARG2 TO ALL UPPER PUSH R4 ; SAVE POINTER TO NEXT CHAR ; FIRST CLEAR OUT OLD CONVERT FLAGS MOV #SIZ,R3 ; R3=SIZE MOV #ARG2CA,R4 ; R4-> STRING TO CLEAR OUT 65$: CLRB (R4)+ ; CLEAR OUT OLD FLAG SOB R3,65$ ; GO CLEAR NEXT IF NOT DONE MOV #ARG2CA,R4 ; R4->STRING HOLDING FLAGS MOV ARG2,R5 ; R5-> STRING TO CONVERT MOV #SIZ,R3 ; R3= SIZE OF STRING CALL CAPIT ; GO CONVERT TO ALL UPPERS POP R4 ; RESTORE POINTER TO NEXT CHAR CALL CMPSTR ; Go compare BCC 70$ ; Branch if not equal ; SET UP REGISTERS FOR CONVERTING ARG2 TO LOWER 99$: MOV #ARG2CA,R4 ; R4->STRING HOLDING FLAGS MOV ARG2,R5 ; R5-> STRING TO CONVERT MOV #SIZ,R3 ; R3= SIZE OF STRING CALL UNCAP ; GO CONVERT UPPER/LOWER BR 100$ ; Go set carry 70$: CMPB #SPACE,(R4) ; Any characters left? BEQ 90$ ; No, branch CMPB #ASTRIX,(R4) ; Is this char a "*" ? BNE 80$ ; No, branch TSTB (R4)+ ;Skip * in building the string 80$: MOVB (R4)+,(R1)+ ; Append next character BR 60$ ; Go compare 90$: TST (PC)+ ; No match, clear carry 100$: SEC ; Match found, set carry POP R5 ; Restore register POP R3 ; Restore register POP R2 ; Restore register POP R1 ; Restore register POP R0 ; Restore register RETURN .DSABL LSB .SBTTL CLNVAR - Clean variable buffer ;+ ; CLNVAR - This routine stores the different iterations of the command ; in VARCMD. This word must be cleared before each iteration. ; ; This routine is called from: COMPAR ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects NO registers. ;- .ENABL LSB CLNVAR:: PUSH R0 ; Save registers PUSH R1 ; Ditto MOV #VARCMD,R0 ; Variable commands MOV #SIZ,R1 ; R1 = Size of def. cmd. 10$: MOVB #NULL,(R0)+ ; Store a null SOB R1,10$ ; Count it and loop if more POP R1 ; Restore R1 POP R0 ; Restore R2 RETURN .DSABL LSB .SBTTL CRECMD Create commands for UCL definitions ;+ ; CRECMD - This routine will be used to create user defined ; commands. The file UCL.DAT will contain the information ; concerning new commands. ; ; This routine is called from: MAIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 ;- CRECMD:: .PURGE #OUTCHN CALL CHKLEN ; Check length of command and def TSTB GOODLN ; Both lengths OK ? BNE 30$ ; NO, branch CALL OPEN ; Go open file CALL INSERT ; Go try to store CMD! 30$: RETURN ; Return to caller .SBTTL OPEN Open command file ;+ ; OPEN - Open the existing command file or create a new one if there ; is none. If it does not exist then you must initialize the ; new file and close the channel to make the file permanent ; and the open it again for processing. ; ; This routine is called from: CRECMD ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 ;- .ENABL LSB OPEN:: CALL HOWBIG ; Find file size CALL LOOK ; Perform lookup BCC 30$ ; Branch if file exist .ENTER #EMTARE,#OUTCHN,#FSPEC,FSIZE ; Create file BCC 20$ ; Branch if no error CMPB @#ERRBYT,#SPC ; Was there no space? BEQ 10$ ; Yes, branch ;+ ;ERROR .ERR #ERRARE,#CHA,LEVEL=F,RETURN=NO,FILE=#FSPEC ; 10$: .ERR #ERRARE,#NRM,LEVEL=F,RETURN=YES,FILE=#FSPEC ; ;- .EXIT 20$: CALL DEFSPC ; Go find out buffer size CALL INIFIL ; Initialize file CALL LOOK ; Go open channel again 30$: RETURN ; Return to caller .DSABL LSB .SBTTL INIFIL - Initialize the file ;+ ; INIFIL - The command file is initialized with blanks. ; The file is filled with blanks because random data ; from the disk should not interfere. ; ; This routine is called from: OPEN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R4 ;- .ENABL LSB INIFIL::INCB INIFLG ; Set flag coming from INIFIL CALL IEREAD ; Read the blocks CLR BLKNUM ; Set block # to 0 MOV BLKN1,R2 ; R2 -> buffer MOV R2,R0 ; R0 -> buffer MOV WDCNT,R1 ; R1 = # of words in buffer ASL R1 ; R1 = # of bytes in buffer 10$: MOVB #SPACE,(R0)+ ; Init to blank SOB R1,10$ ; Repeat until done MOV R2,R3 ; R3 -> buffer MOVB #XCLAIM,(R2)+ ; Move "!" into 1st spot MOV ..CMDS,R0 ; R0 = # of def. cmds. max MOV #FIVE,R4 ; R4 = counter for loop 20$: MOV R0,R1 ; R1 = remaining bits BIC #^C7,R1 ; Clear all other bits BIS #ZERRO,R1 ; Set the "60" bits PUSH R1 ; Save on the stack ASR R0 ; Roll out bit ASR R0 ; Roll out bit ASR R0 ; Roll out bit SOB R4,20$ ; NOW THE NUMBER OF COMMANDS IS ON THE STACK, GO MOVE IT OFF MOV #FIVE,R4 ; R3 = loop counter 30$: CMPB (SP),#ZERRO ; Is char a "0" ? BNE 40$ ; No, branch TSTB SIGFIG ; Is # significant ? BNE 40$ ; Yes, branch TSTB (SP)+ ; Pop stack BR 50$ ; Skip next 40$: INCB SIGFIG ; Set sigfig flag MOVB (SP)+,(R2)+ ; Move character 50$: SOB R4,30$ ; Go loop if not done CALL IWRITE ; Write the blocks back 60$: .CLOSE #OUTCHN ; Make file permanent RETURN ; Return to caller .DSABL LSB .SBTTL HOWBIG - Calculate the size of UCL.DAT ;+ ; HOWBIG - This routine calculates the size of UCL.DAT and moves the ; value into VALUE. ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine is called from: OPEN ; SHOCMD ; ; This routine affects the contents of : R3 -> R5 ;- .ENABL LSB HOWBIG::MOV #CMDPB0,R3 ; R3 = # cmds. in 1ST block CLR R4 ; R4 = Size of UCL.DAT MOV ..CMDS,R5 ; R5 = # of def. commands CMP R5,R3 ; 1 block of def. cmds ? BLT 20$ ; No, branch SUB R3,R5 ; Subt. 1 blk. of def. cmds. ADD #CMDDEF,R4 ; Count it MOV #CMDPBK,R3 ; R3 = # cmds. in 1 block 10$: CMP R5,R3 ; Full block of commands ? BLT 20$ ; No, branch SUB R3,R5 ; Subt. 1 blk. of def. cmds. ADD #CMDDEF,R4 ; Count it BR 10$ ; Go loop ; NOW DETERMINE IF THERE IS A PARTIAL BLOCK OF DEFINED COMMANDS 20$: TST R5 ; Partial block ? BEQ 60$ ; No, branch MOV #DEFPBK,R3 ; R3 = # of def. cmds. / block 30$: CMP R5,R3 ; Full block of definitions ? BLT 40$ ; No, branch SUB R3,R5 ; Subt. 1 blk of defintions INC R4 ; Count it BR 30$ ; Go loop 40$: TST R5 ; Partial block of definitons? BEQ 50$ ; No, branch INC R4 ; Yes, count it 50$: INC R4 ; Count blk of def. cmds. 60$: MOV R4,FSIZE ; Store file size CMP TOTBLK,FSIZE ; All of data file read in ? BLT 70$ ; No, branch MOV FSIZE,TOTBLK ; Only use buffer with data 70$: MOV TOTBLK,R4 ; R4 = blocks in buffer SWAB R4 ; R4 = words in buffer MOV R4,WDCNT ; WDCNT = words in buffer MOV R4,WWDCNT ; WWDCNT = words in buffer RETURN ; Return .DSABL LSB .SBTTL WRITE - .WRITEW implemented ;+ ; WRITE - This routine writes out the blocks with newly defined commands ; and definitons. ; ; This routine is called from: INSERT ; ; This routine expects the following to already ; have been set up when entered: ; ; R2 -> Buffer that contains material to write ; R3 -> Block number ; R4 -> Wordcount ; ; This routine affects the contents of : R0 ;- .ENABL LSB WRITE:: .WRITW #EMTARE,#OUTCHN,BLKN1,WWDCNT,BLKNUM ; Write blocks BCC 20$ ; Branch if no error ;+ ;ERROR 10$: .ERR #ERRARE,#OUT,LEVEL=F,RETURN=N,FILE=#FSPEC ; ;- 20$: RETURN ; Return .DSABL LSB .SBTTL IWRITE - Initial .WRITEW implemented ;+ ; IWRITE - This routine writes out blanks when creating the new UCL.DAT ; ; This routine is called from: INIFIL ; ; This routine expects the following to already ; have been set up when entered: ; ; R2 -> Buffer that contains material to write ; R3 -> Block number ; R4 -> Wordcount ; ; This routine affects the contents of : R0 and R2 ;- .ENABL LSB IWRITE:: MOV WDCNT,-(SP) ; Save in case we modify it ;+ ; Write the first block, with '!' and ASCII command count ; The '!' and cmd count will be blanked out for further WRITES ;- 10$: .WRITW #EMTARE,#OUTCHN,BLKN1,WDCNT,BLKNUM ; Write blocks BCS 220$ ; Error, tell user ADD TOTBLK,BLKNUM ; Update write block-pointer ;+ ; See if there is more to write out, adjust WDCNT if less than full buffer ;- MOV FSIZE,R0 ; R0 = Total blocks in file SUB BLKNUM,R0 ; R0 = Blocks left unwritten BLE 70$ ; No blocks left, finished CMP R0,TOTBLK ; A full buffer left ? BGE 24$ ; Yes, keep full word count CLR R2 ; Compute new word count 22$: ADD #WDSBLK,R2 ; R2 = Words to write SOB R0,22$ ; Count unwritten blocks MOV R2,WDCNT ; Set count for WRITE ;+ ; Blank out the '!' and ASCII command count ;- 24$: MOV #SIZ,R0 ; R0 ->Beginning of UCL.DAT MOVB #SPACE,R2 ; R2 = space 26$: MOVB R2,(R3)+ ; Blank out 1st 16 bytes SOB R0,26$ ; Dec. & branch if not done BR 10$ ; Write out another block ;+ ; Restore WDCNT and RETURN to caller ;- 70$: MOV (SP)+,WDCNT ; Fix in case we modified it RETURN ; Return ;+ ;ERROR 220$: .ERR #ERRARE,#OUT,LEVEL=F,RETURN=N,FILE=#FSPEC ; ;- .DSABL LSB .SBTTL SWRITE - SHOCMD's .WRITW implemented ;+ ; SWRITE - This routine outputs the buffer that SHOCMD fills with ; commands when it displays all the commands. The output buffer ; is at most one block long. ; ; This routine is called from: SHOCMD ; PCMD ; PKMO ; ; This routine expects the following to already ; have been set up when entered: ; ; CHAN0 = channel number to perform the output ; MYBUFF = address of output buffer ; SWDCNT = number of words to output ; SHONUM = block number of where to begin the write in UCL.DAT ; ; This routine affects the contents of : R0 and R4 ;- .ENABL LSB SWRITE::.WRITW #EMTARE,#CHAN0,MYBUFF,SWDCNT,SHONUM ; Write blocks BCC 10$ ; Branch if no error ;+ ;ERROR .ERR #ERRARE,#OUT,LEVEL=F,RETURN=N,FILE=#FSPEC ; ;- 10$: MOV MYBUFF,R4 ; Reset output buffer INC SHONUM ; Bump block # RETURN ; Return .DSABL LSB .SBTTL INSERT Store the new command ;+ ; INSERT - This routine attempts to insert the newly defined command ; into UCL.DAT. If the command already exists, then this routine ; calls QUERY to determine whether the user wants to either ; replace or delete the current demand. ; ; This routine is called from: CRECMD ; ; This routine does not expect anything to already ; have been set up when entered: ; ; This routine affects the contents of : R0 -> R3 & R5 ;- .ENABL LSB INSERT:: ;+ ; Read in the command table ;- CLR BLKNUM ; Set block number to 0 TSTB INIFLG ; Gone thru INIFIL ? BNE 10$ ; Yes, skip allocating buffer,was already done CALL DEFSPC ; Go allocate buffers 10$: CALL IEREAD ; Go read 10 blocks CALL SETNUM ; Go setup # of commands in UCL.DAT CALL MOBKS ; Go determine if more blks of defined cmds. CALL DEFCMD ; Go determine # of def. cmds. in memory CALL FIXINP ; Go set starless string to compare with ;+ ; Look for a match in the database ;- MOV BLKN1,R2 ; R2 -> Buffer ADD #SIZ,R2 ; R2 -> First spot for command in data base MOV R2,R1 ; R1 -> First spot for command in data base CLR R3 ; R3 = Counter for commands processed 20$: CMPB (R1),#SPACE ; R1 ->Defined command. Is there one there? BEQ 22$ ; No, look at next spot CALL COMPAR ; Go compare strings BCS 100$ ; Found a match 22$: ADD #SIZ,R1 ; R1 -> Next defined command INC R3 ; R3 = Counter for commands processed so far CMP R3,MAXNUM ; Processed all the commands? BLT 20$ ; Go look at next entry ;+ ; Command not in memory, read in more ;- TSTB MORBKS ; More blocks with defined commands ? BEQ 30$ ; No, branch ADD R3,NUMPRO ; Count commands processed CALL IEREAD ; Go read more commands CALL MOBKS ; Go determine if more blks of defined cmds. CALL DEFCMD ; Go determine # of def. cmds. in memory MOV BLKN1,R1 ; R1 -> 1st spot in latest read CLR R3 ; R3 = commands processed so far in curr. blk BR 20$ ; Go start searching again ;+ ; The entire data base has been searched and no match has been found ;- 30$: TSTB DELETE ; User deleting command that isn't there ? BNE 150$ ; YES, tell him so with error message ;+ ; Look for place to insert the new command ;- TSTB CUTOFF ; Is whole file in memory ? BNE 45$ ; Yes, skip the reading. Nothing new to read. CLR BLKNUM ; Init block number 40$: CALL IEREAD ; Go read buffer full of blocks CALL MOBKS ; Go determine if more blks of defined cmds. CALL DEFCMD ; Go determine # of def. cmds. in memory 45$: CLR R0 ; R0 = counter for commands processed MOV BLKN1,R1 ; R1 -> 1st spot of UCL.DAT ADD #SIZ,R1 ; R1 -> 1st defined command 50$: CMPB (R1),#SPACE ; Is 1st char a blank ? BEQ 110$ ; Branch if it's a spot to insert command INC R0 ; Increment counter for # of checks CMP R0,MAXNUM ; processed all commands in memory ? BEQ 55$ ; yes, branch ADD #SIZ,R1 ; Point to next entry BR 50$ ; Go loop 55$: TSTB MORBKS ; More blocks to search ? BEQ 140$ ; No, branch BR 40$ ; Go read next blocks ; The command was found in the database 100$: TST DELETE ; Do we want to DELETE the command ? BNE 120$ ; Yes, delete it TSTB STARFN ; Is there a STAR in the command ? BEQ 130$ ; No, it's a simple REPLACE MOV R3,R0 ; R0 = # of commands processed so far ; Handle '*' as if new cmd ; Insert command and definition at the current location in database 110$: CALL STONEW ; Go store new command BR 200$ ; Finished, exit ; Delete command and definition from the database 120$: CALL DELEET ; Call delete routine BR 200$ ; Finished, exit ; Insert definition at the current location in database, keep orig cmd 130$: CALL REPLAC ; Call replace routine BR 200$ ; Finished, exit ;+ ;ERROR 140$: .ERR #ERRARE,#FLL,LEVEL=F,RETURN=Y,FILE=#FSPEC; Data base file full ; BR 200$ ; Done with routine 150$: .ERR #ERRARE,#EXS,LEVEL=F,RETURN=Y ; Deleteing non-existent cmd ; ;- 200$: RETURN .DSABL LSB .SBTTL FIXINP - Fix the input command if it contains a "*" ;+ ; FIXINP - This routine removes the star from the input command if there ; is one present. This is done so the command will match a command ; in the data base. ; ; This routine does not expect anythimng to already ; have been set up when entered. ; ; This routine affects the contents of : R1 & R2 ; ;- .ENABL LSB FIXINP::MOV #NEWCMD,ARG1 ; ASSUME THERE'S NO STAR MOV #NEWCMD,R1 ; R1 -> Def. cmd MOV R1,R2 ; R2 -> DEF. CMD ADD #SIZ,R2 ; R2 -> END OF DEF. CMD 10$: CMPB #ASTRIX,(R1)+ ; FOUND A STAR ? BEQ 20$ ; YES, BRANCH CMP R1,R2 ; PROCESSED ALL CHARACTER ? BEQ 60$ ; YES, BRANCH BR 10$ ; GO CHECK NEXT CHARACTER 20$: MOV #NEWCMD,R1 ; R1 -> DEF. CMD MOV #TEMPBF,R2 ; R2 -> BUFFER 30$: CMPB (R1),#ASTRIX ; IS THIS THE "*" ? BEQ 50$ ; YES, BRANCH 40$: MOVB (R1)+,(R2)+ ; MOVE A CHAR BNE 30$ ; GO MOVE NEXT CHAR MOV #TEMPBF,ARG1 ; ARG1 -> STARLESS COMMAND INCB STARFN ; Indicate star found BR 60$ ; GO LEAVE ROUTINE 50$: TSTB (R1)+ ; SKIP "*" BR 40$ ; GO MOVE NEXT CHAR 60$: MOV ARG1,R5 ; R5 -> AREA TO UNCONVERT MOV #ARG1CA,R4 ; R4 -> STRING TO HOLD FLAGS MOV #SIZ,R3 ; R3 = LENGTH TO DO COMPARES CALL CAPIT ; GO CONVERT TO ALL UPPER RETURN ; DONE ADJUSTING COMMAND .DSABL LSB .SBTTL DEFSPC - Define the space for the buffers ;+ ; DEFSPC - This routine defines the space for the buffers in memory. ; There must be at least two blocks of memory available or ; UCL will not be able to run. ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R1 ;- .ENABL LSB DEFSPC::.SETTOP #-2 ; Try for all memory 10$: MOV R0,BTOP ; BTOP = address allocated SUB BLKN1,BTOP ; BTOP = amt. of buffer space CLR R0 ; Counter of # of blocks MOV BTOP,R1 ; R1 = amt. of buffer space CMP #TWOBKB,R1 ; At least 2 blocks ? BHI 60$ ; No, branch 20$: SUB #BYTBLK,R1 ; Sub 1 block of bytes INC R0 ; Count it CMP #BYTBLK,R1 ; Block of bytes left ? BLOS 20$ ; Yes, branch CMP R0,FSIZE ; All of file in memory ? BGE 30$ ; Yes, branch MOV R0,TOTBLK ; TOTBLK= # of blocks in mem BR 40$ ; Skip next 30$: MOV FSIZE,R0 ; R0 = # of blocks in file MOV FSIZE,TOTBLK ; TOTBLK = # blocks in buffer 40$: CLR WDCNT ; Clear word count counter 50$: ADD #WDSBLK,WDCNT ; 256. more words processed DEC R0 ; R0 = counter for # of blocks BNE 50$ ; Branch if more blocks MOV WDCNT,WWDCNT ; WWDCNT= # of words for write BR 70$ ; Leave routine ;+ ;ERROR 60$: .ERR #ERRARE,#MEM,LEVEL=F,RETURN=NO ; Insufficient memory message ; ;- 70$: RETURN .DSABL LSB .SBTTL REPLAC - Replace command ;+ ; REPLAC - In this routine there a multiplication performed. ; One of the multiplicands is 128.(size of one KMON command) ; and the other multiplicand is ALWAYS: 0 <= MULTIPLICAND <= 32. ; Having one multiplicand 0 <= MULTIPLICAND <= 32. ; allows the SWAB and ASR/ASL instructions to be executed and ; ensure that the sign bit will be zero. Then when the ASR ; instruction is executed immediately after the SWAB , the net ; result is the same as having multiplied by 128. ; Or when the ASL instruction is executed immediately after ; the SWAB instruction , the net result is the same ; as having multiplied by 512. ; ; ; This routine is called from: QUERY ; ; This routine expects the following to already ; have been set up when entered: ; ; R3 = Counter for commands processed ; NUMPRO = number of previously processed defined commands ; ; This routine affects the contents of : R0 -> R5 ;- .ENABL LSB REPLAC::MOV NUMPRO,R2 ; R2 = # prev. proc. def. cmds ADD R2,R3 ; R3 = total # processed MOV #DEFPBK,R2 ; R2 = # of def's per block CLR R1 ; R1 = counter for block # CMP R2,R3 ; 1 block of definitions ? BGT 20$ ; No, branch 10$: SUB R2,R3 ; Subt 1 blk of defintions INC R1 ; Count it CMP R2,R3 ; Another block ? BLE 10$ ; No, branch ;+ ; R1 NOW HAS THE NUMBER OF FULL BLOCKS TO OFFSET INTO DEF'S TO READ THE ; CORRECT BLOCK NUMBER ;- 20$: CLR R2 ; Clear high byte MOVB CMDBKS,R2 ; R2 = # of command blocks ADD R2,R1 ; R1 = blk. # containing d.c. MOV R1,BLKNUM ; Save number in BLKNUM CMP R1,TOTBLK ; Is block in memory ? BGT 30$ ; No, branch ; NOW CALCULATE THE OFFSET TO THE BLOCK SWAB R1 ; Mult. by 256. ASL R1 ; Mult. by 512. MOV BLKN1,R4 ; R4 = start of buffer ADD R1,R4 ; R4 -> beginning of def. blk. MOV R4,BLKN1 ; Save address in BLKN1 ; NOW GET THE PROPER OFFSET WITHIN THE BLOCK SWAB R3 ; Mult. by 256. ASR R3 ; Mult. by 128. ADD R4,R3 ; R3 -> correct spot for repl. BR 40$ ; Skip next ; THE BLOCK NUMBER ISN'T IN MEMORY, NOW WE WILL READ IT INTO THE FIRST BLOCK 30$: .READW #EMTARE,#OUTCHN,BLKN1,#256.,R1 BCS 90$ ; Branch if error ; NOW OFFSET TO THE CORRECT SPOT SWAB R3 ; Mult. by 256. ASR R3 ; Mult. by 128. MOV BLKN1,R2 ; R3 -> Beg. of buffer ADD R2,R3 ; R3 -> correct spot for repl. ; NOW ITS TIME TO DO THE REPLACING OF THE DEFINITION 40$: MOV R3,R1 ; R1 -> Spot to replace MOV #CMDSIZ,R4 ; R4 = char counter CLR R5 ; Clear high byte MOVB #SPACE,R5 ; R5 = blank 50$: MOVB R5,(R1)+ ; Blank location SOB R4,50$ ; Branch if not done ; NOW PUT IN THE NEW DEFINITION IF WE ARE REPLACING, NOT DELETING TSTB DELETE ; In delete mode ? BNE 80$ ; Yes, branch MOV #KMOCMD,R2 ; R3 -> Definition to insert MOV LENKMO,R0 ; R0 = length of definition 60$: TSTB (R2) ; Is char a null ? BNE 70$ ; No, branch MOVB #177,(R2) ; Replace it with a "177" 70$: MOVB (R2)+,(R3)+ ; Move char of new definition SOB R0,60$ ; Branch if not done 80$: .WRITW #EMTARE,#OUTCHN,BLKN1,#256.,BLKNUM ; Write replaced block BCC 100$ ; Branch if no error ;+ ;ERROR 90$: .ERR #ERRARE,#OUT,LEVEL=F,RETURN=N ; Issue error message ; ;- 100$: RETURN .DSABL LSB .SBTTL DELEET - Delete old command ;+ ; DELEET - This routine deletes the old command from UCL.DAT and inserts the ; new definition into UCL.DAT. This routine then calls REPLAC ; which will blank over the old definiton. ; ; This routine is called from: QUERY ; ; This routine expects the following to already ; have been set up when entered: ; ; R3 = Counter for commands processed so far ; ; This routine affects the contents of : R0 -> R2 ;- .ENABL LSB DELEET::MOV R1,R0 ; R0 -> command to delete MOVB #SPACE,R2 ; R2 = blank ADD #SIZ,R0 ; R0 = command size 10$: MOVB R2,(R1)+ ; Blank out the def. command. CMP R0,R1 ; Done blanking defined commd? BNE 10$ ; No, branch ; NOW WRITE OUT THE BLANKED OUT DEFINED COMMAND MOV BLKNUM,R1 ; R1 = blk # we've read up to MOV TOTBLK,R2 ; R2 = # of blocks in memory SUB R2,R1 ; R1 = blk # that last read ; began with .WRITW #EMTARE,#OUTCHN,BLKN1,WDCNT,R1 ; Perform the write BCC 20$ ; Branch if no error ;+ ;ERROR .ERR #ERRARE,#OUT,LEVEL=F,RETURN=N ; Issue error message ; ;- ; NOW BLANK OUT THE DEFINITION 20$: CALL REPLAC ; Call REPLACE RETURN .DSABL LSB .SBTTL STONEW Store new command ;+ ; STONEW - This routine stores the newly entered defined command ; and the defintion into the correct spots in UCL.DAT. ; ; This routine is called from: INSERT ; ; This routine expects the following to already ; have been set up when entered: ; ; R0 = Counter for # of commands processed ; R1 -> Blank spot in data base ; CMDSIZ = Length of spot in data base for definition ; KMOCMD = ASCII of KMON command ; LENAMB -> Length of ambiguous size ; LENEW = Length of new command ; LENKMO -> Length of KMON command ; NEWCMD -> ASCII KMON command entered ; ; This routine affects the contents of : R1 and R5 ;- STONEW:: ; Set up registers, uncase NEWCMD MOV #ARG1CA,R4 ; R4->STRING HOLDING FLAGS MOV #NEWCMD,R5 ; R5-> STRING TO CONVERT MOV #SIZ,R3 ; R3= SIZE OF STRING CALL UNCAP ; GO CONVERT TO ALL UPPERS ; Move NEWCMD into the database, stopping at MOV #NEWCMD,R5 ; R5 -> Ascii command entered 10$: MOVB (R5)+,(R1)+ ; Store character TSTB (R5) ; Next char a null ? BNE 10$ ; No, branch ; Set up registers, uncase KMOCMD 20$: MOV #KMOCAS,R4 ; R4->STRING HOLDING FLAGS MOV #KMOCMD,R5 ; R5-> STRING TO CONVERT MOV #CMDSIZ,R3 ; R3= SIZE OF STRING CALL UNCAP ; GO CONVERT UPPER/LOWER ; Move KMOCMD into the database CALL OFFDEF ; Go find spot for definition 30$: RETURN .SBTTL OFFDEF Offset to definition is calculated ;+ ; OFFDEF - This routine calculates the correct block numbers for the ; defined command and definition to be inserted or executed. ; If this routine is called from INSERT, then if the block ; that will contain the definition is in memory, then the insertiion ; is performed and the write is simple, just write out everything. ; If the definition is not in memory, then the correct block ; where the definition is to be inserted is read into the first block ; of the buffer. The insertiion is performed and then the block is ; written out to the correct block within UCL.DAT. ; This routine stores 177 's in place of nulls between commands ; so the user may edit the ASCII file UCL.DAT. (Editors ; don't like zeroes.) ; ; If this routine is called from FRMCMD, then this routine will point ; to the spot in the data base where the definition. If the ; definition is in memory then the calculation to the definition ; is performed. If the definition is not in memory, then the block ; that contains the definition is read into the first block of the ; buffer. Then this routine will point to the correct definition ; to be executed. ; ; This routine is called from: STONEW ; FRMCMD ; ; This routine expects the following to already ; have been set up when entered: ; ; BLKN1 = Beginning of buffer ; BLKNUM = Blk # we've read up to ; TOTBLK = Total blks in buffer ; STARFN = Asterisk was found in the definition ; EXECMD = Executing a command (don't update database) ; CUTOFF = All of ucl.dat is in memory ; ; R0 = # of commands processed so far ; ; This routine affects the contents of : R0 -> R5 ;- .ENABL LSB ;+ ; THE FIRST SECTION PUTS THE ADDRESS OF THE BEGINNING OF THE BUFFER INTO ; R3, THROUGHOUT THE ROUTINE R3 WILL BE ADDED TO SO THAT FINALLY IT WILL ; CONTAIN THE ACTUAL ADDRESS OF THE SPOT FOR THE DEFINITION TO BE INSERTED. ;- OFFDEF::MOV BLKN1,R3 ; R3 -> Beginning of buffer ;+ ; CALCULATE THE ACTUAL BLOCK NUMBER THAT THE DEFINED COMMAND WAS INSERTED ; INTO. CALCULATE THE BLOCK # FROM WHERE THE LAST READ WAS STARTED. ;- MOV BLKNUM,R5 ; R5 = Blk # we've read up to MOV TOTBLK,R2 ; R2 = Total blks in buffer SUB R2,R5 ; R5 = Blk # from last read CLR R2 ; R2 will be counter of blocks 10$: CMP R0,#CMDPBK ; 1 blk of defined commands ? BLT 20$ ; No, branch SUB #CMDPBK,R0 ; Subt 1 blk of def. cmds. INC R2 ; Count it BR 10$ ;+ ; NOW ADD THE BLOCK # FROM WHERE THE LAST READ BEGAN TO THE # OF FULL BLOCKS ; OF DEFINED COMMANDS AND THE SUM IS THE TOTAL # OF FULL BLOCKS OF DEFINED ; COMMANDS THERE ARE BEFORE THE BLOCK WHERE THE DEFINITION IS TO BE INSERTED ;- 20$: ADD R5,R2 ; R2 = # of full blks of ; def. cmds. before current ; defined command ;+ ; MUST KEEP TRACK OF THE CORRECT RELATIVE BLOCK NUMBER WITHIN UCL.DAT ; WHERE THE DEFINITION IS GOING TO BE. THIS NUMBER WILL BE THE NUMBER OF ; DEFINED COMMAND BLOCKS ADDED TO EIGHT TIMES THE NUMBER OF FULL BLOCKS ; OF DEFINED COMMANDS. THIS IS BECAUSE EACH FULL BLOCK OF DEFINED COMMANDS ; USES 8 BLOCKS OF DEFINITION SPACE. ; IN THIS ROUTINE THE THREE ASL's IS EQUIVALENT TO MULTIPLYING BY EIGHT. ;- MOV R2,R4 ; R4 = # of full def. cmd.bks. ASL R4 ; Multiply block # by 2 ASL R4 ; Multiply block # by 4 ASL R4 ; Multiply block # by 8. ;+ ; NOW ADD THE 8 BLOCK OFFSETS TO THE START OF THE DEFINTIONS AND THE SUM ; WILL BE THE BEGINNING OF THE CORRECT 8 BLOCK SEGMENT FOR THE DEFINITION ;- CLR R5 ; Clear high byte of R5 MOVB CMDBKS,R5 ; R5 = # of defined cmd. blks. ;+ ; ADD THE # OF FULL BLOCKS OF DEFINITIONS TO THE START OF THE DEFINTIONS ; AND THE RESULT IS THE CORRECT OFFSET TO THE 8 BLOCK SEGMENT FOR THIS ; DEFINTION. ;- ADD R5,R4 MOV R4,WBLOCK ; Store it in WBLOCK ;+ ; R4 = BLOCK # THAT 8 BLOCK SEGMENT BEGINS. NOW WE MUST CALCULATE THE ADDRESS ; OF THIS BLOCK. THIS IS ACCOMPLISHED BY MULTIPLYING IT BY # OF BYTES / BLOCK ; THEN ADD THIS TO THE BEGINNING OF THE DEFINTIONS AND THE SUM WILL ; THEN POINT TO THE BEGINNING OF THE CORRECT 8 BLOCK SEGMENT FOR THE DEFINTION ; TO BE INSERTED. ; THE MULTIPLICATION BY # OF BYTES / BLOCK IS ACCOMPLISHED BY: ; ; 1. SWAB THE REGISTER, THIS MULTIPLIES IT BY 256. ; 2. ASL THE REGISTER, THIS MULTIPLIES IT BY 2. ; THE NET EFFECT IS MULTIPLYING BY 512. ( THE # OF BYTES / BLOCK ) ;- MOV R4,R5 ; R5 = block # of definition SWAB R5 ; Multiply by 256. ASL R5 ; Multiply by 2 ; R5 NOW CONTAINS THE CORRECT NUMBER OF BYTES TO OFFSET. ADD R5,R3 ; R3->correct 8 blk segment ; of definitions ;+ ; NOW CALCULATE THE CORRECT BLOCK # WITHIN THE 8 BLOCK SEGMENT THAT THE ; DEFINITION WILL BE INSERTED. R4 WILL CONTAIN THE CORRECT NUMBER OF ; FULL BLOCKS OF DEFINITIONS BEFORE THE BLOCK WHERE THE DEFINITION IS TO ; BE INSERTED. ; ; NOTE: R0 NOW CONTAINS THE # OF COMMANDS WITHIN 1 BLOCK OF DEFINED COMMANDS ; THAT ALREADY HAVE A PREVIOUSLY-DEFINED COMMAND IN THEM. NOW SUBTRACT ; # OF DEFINED COMMANDS / BLOCK TO FIND OUT HOW MANY BLOCKS OF ; DEFINIITIONS TO OFFSET. ;- CLR R4 30$: CMP R0,#DEFPBK ; Block full of defintions ? BLT 40$ ; No, branch SUB #DEFPBK,R0 ; Subtract 1 blk of defs. INC R4 ; Count it BR 30$ ; Yes, branch ;+ ; R4 CONTAINS THE CORRECT BLOCK OFFSET WITHIN THE 8 BLK SEGMENT. ; ADD THIS TO THE OFFSET OF THE 8 BLOCK SEGMENT. THE SUM WILL BE ; THE CORRECT BLOCK NUMBER WITHIN THE 8 BLOCK SEGMENT. ;- 40$: ADD R4,WBLOCK ; Add to relative blk counter ;+ ; MUST STILL CALCULATE THE CORRECT ADDRESS OF WHERE TO INSERT THE DEFINTION. ; R4 CONTAINS THE CORRECT BLOCK OFFSET WITHIN THE 8 BLOCK SEGMENT, SO MULTIPLY ; THIS BY # OF BYTES / BLOCK TO GET THE PROPER OFFSET WITHIN THE 8 BLOCK ; SEGMENT. ; THE MULTIPLICATION BY # OF BYTES / BLOCK IS ACCOMPLISHED BY: ; 1. SWAB THE REGISTER, THIS MULTIPLIES IT BY 256. ; 2. ASL THE REGISTER, THIS MULTIPLIES IT BY 2. ; THE NET EFFECT IS MULTIPLYING BY 512. ( THE # OF BYTES / BLOCK ) ;- SWAB R4 ; Multiply by 256. ASL R4 ; Multiply by 2 ; R4 NOW CONTAINS THE CORRECT NUMBER OF BYTES TO OFFSET. ADD R4,R3 ; R3 -> correct blk for def. ;+ ; NOW ITS TIME TO DO THE WRITING OF THE DEFINED COMMAND AND THE DEFINITION. ; IF THE WHOLE FILE IS IN MEMORY THEN THE WRITE IS JUST WRITING OUT THE WHOLE ; FILE. IF IT IS NOT, THEN IS THE DEFINITION IN MEMORY(THE DEFINED COMMAND ; IS IN MEMORY) ? IF IT IS THEN WRITE OUT THE DEFINED COMMAND AND THEN ; WRITE THE DEFINITION. IF THE DEFINITION IS NOT IN MEMORY, THEN WRITE OUT ; THE DEFINED COMMAND AND THEN READ IN THE CORRECT BLOCK NUMBER FOR ; THE DEFINITION TO BE INSERTED. READ THE CORRECT DEFINIION BLOCK INTO THE ; FIRST BLOCK OF THE BUFFER. THEN DO THE INSERTION AND THEN WRITE IT OUT ; TO THE CORRECT RELATIVE BLOCK IN UCL.DAT. ;- TSTB CUTOFF ; All of ucl.dat in memory ? BEQ 80$ ; No, branch ; NOW CALCULATE WHICH DEFINTION WITHIN THE 1 BLOCK WHICH IS THE SPOT FOR DEF. SWAB R0 ; Mult. offset by 256. ASR R0 ; Net mult. by 128. ADD R0,R3 ; R3 -> spot to insert definion TSTB EXECMD ; Executing a command ? BNE 300$ ; Yes, Return now CLR BLKNUM ; Start write from beginning BR 260$ ; No, Move command, then return ; .............. ;+ ; THE READ WAS NOT CUTOFF, THIS MEANS THAT THE CORRECT SPOT FOR ; THE DEFINITION MAY BE IN MEMORY OR IT MAY STILL BE OUT ON THE ; MEDIA. IF IT IS IN MEMORY THEN JUST INSERT THE DEFINITON AND ; WRITE OUT ALL OF MEMORY. WBLOCK CONTAINS THE RELATIVE BLOCK ; NUMBER THAT THE DEFINION WILL BE INSERTED INTO. ;- 80$: CMP WBLOCK,TOTBLK ; IS DEFINTION IN MEMORY ? BGE 140$ ; NO, BRANCH ;+ ; DEFINITION IS IN MEMORY, NOW JUST STORE THE DEFINITION. ; DON'T FORGET TO OFFSET THE CORRECT NUMBER WITHIN THE BLOCK ;- SWAB R0 ; Mult. by 256. ASR R0 ; R0 = correct offset within the block ADD R0,R3 ; R3 - > correct spot to insert TSTB EXECMD ; Executing a command ? BNE 300$ ; Yes, return ; THIS NEXT SHORT SECTION IS PERFORMED BECAUSE OF THE WAY THAT A ; COMMAND GETTING REPLACED AS THE SAME COMMAND WITH AN ASTERIX IS TREATED. ; IT IS TREATED AS AN INSERTION OF A NEW COMMAND, WHEN ACTUALLY IT IS A ; REPLACEMENT OF AN OLD COMMAND. 90$: TSTB STARFN ; Found a star in the definition ? BEQ 110$ ; No, branch MOV R3,R1 ; R1 -> spot to insert new definition MOV #CMDSIZ,R0 ; R0 = length of command 100$: MOVB #SPACE,(R1)+ ; Move in a space SOB R0,100$ ; Branch if not done 110$: CLR BLKNUM ; Start write from beginning BR 260$ ; Copy def to buffer, return ; .............. ;+ ; THE CORRECT SPOT FOR THE DEFINITON IS NOT IN MEMORY. ; FIRST WRITE OUT THE BLOCK WITH THE DEFINED COMMAND IN IT AND THEN WE MUST ; READ IN THE CORRECT BLOCK FOR THE DEFINION INTO THE FIRST BLOCK, ; PERFORM THE INSERTION AND THEN WRITE OUT THE BLOCK TO THE CORRECT ; RELATIVE BLOCK NUMBER WITHIN UCL.DAT. ;- 140$: MOV R0,R4 ; Save correct offset in r4 TSTB EXECMD ; Executing a command ? BNE 150$ ; Yes, skip the WRITE ; Write the updated command segment out to disk MOV BLKNUM,R2 ; R2 = last block read in MOV TOTBLK,R0 ; R0 = total blocks in buffer SUB R0,R2 ; R2 = block that last read started at MOV R2,BLKNUM ; Start write at beginning of last read CALL WRITE ; Write out file with newly inserted def. cmd. ; NOW READ IN THE BLOCK WHERE THE DEFINITION IS TO BE INSERTED 150$: .READW #EMTARE,#OUTCHN,BLKN1,#256.,WBLOCK BCS 400$ ; Report I/O error ; DON'T FORGET TO OFFSET THE CORRECT NUMBER WITHIN THE BLOCK 160$: MOV BLKN1,R3 ; R3 -> Block just read in MOV R4,R0 ; R0 = # of commands to offset within blk SWAB R0 ; Mult. by 256. ASR R0 ; R0 = correct offset within the block ADD R0,R3 ; R3 - > correct spot to insert TSTB EXECMD ; Executing a command ? BNE 300$ ; Yes, Return now ; THIS NEXT SHORT SECTION IS PERFORMED BECAUSE OF THE WAY THAT A ; COMMAND GETTING REPLACED AS THE SAME COMMAND WITH AN ASTERIX IS TREATED. ; IT IS TREATED AS AN INSERTION OF A NEW COMMAND, WHEN ACTUALLY IT IS A ; REPLACEMENT OF AN OLD COMMAND. ; If '*', there is already a definition in the buffer, so we will ; blank it out to make sure there are no stray characters left over. TSTB STARFN ; Found a star in the definition ? BEQ 180$ ; No, destination is already blank MOV R3,R1 ; R1 -> spot to insert new definition MOV #CMDSIZ,R0 ; R0 = length of command 170$: MOVB #SPACE,(R1)+ ; Move in a space SOB R0,170$ ; Branch if not done ;+ ; SET UP PARAMETERS TO PERFORM A WRITE OF THE FIRST BLOCK IN MEMORY ; TO THE CORRECT RELATIVE BLOCK NUMBER WITHIN UCL.DAT ;- 180$: MOV #WDSBLK,WWDCNT ; Write out 1 block MOV WBLOCK,BLKNUM ; Point to correct block ; Fall through, copy def to buffer ; Copy the definition to the buffer 260$: MOV LENKMO,R0 ; R0 = Length of definition MOV #KMOCMD,R1 ; R1 -> Definition to insert 265$: TSTB (R1) ; Is char a null ? BNE 267$ ; No, branch MOVB #177,(R1) ; Substitute "177" (so we can edit) 267$: MOVB (R1)+,(R3)+ ; Store a character SOB R0,265$ ; Count it and loop if not done 290$: CALL WRITE ; Write defs to disk 300$: RETURN ;+ ;ERROR 400$: .ERR #ERRARE,#INP,LEVEL=F,RETURN=NO ; Issue error message ; ;- .DSABL LSB .SBTTL CHKLEN Check the lengths of the new command and its definition ;+ ; CHKLEN - This routine checks the lengths of the new defined command ; and the new definition. The new defined command may be up to ; 6 characters long and the new definition may be up to 128. ; characters long. ; ; This routine expects the following to already ; have been set up when entered: ; ; NEWCMD = New defined command ; KMOCMD = New KMON defined command ; ; This routine affects the contents of : R0, R2 and R5 ;- .ENABL LSB CHKLEN:: CLR GOODLN ; GOODLN = Flag for good command lengths ; Validate the length of the command string (New Command) MOV #NEWCMD,R5 ; R5 -> defined command MOV #SIZ+1,R2 ; Set limit on string length 10$: TSTB (R5)+ ; Character a null ? BEQ 20$ ; Yes, end of string SOB R2,10$ ; Repeat for legal length BR 50$ ; String is too long ; Validate the length of the definition string (KMON Command) 20$: MOV #KMOCMD,R5 ; R5 -> Definition MOV #CMDSIZ+1,R2 ; Set limit on string length 30$: TSTB (R5)+ ; Character a null ? BEQ 60$ ; Yes, end of string SOB R2,30$ ; Go test next char ; Command or Definition too long, display message ;+ ;ERROR 50$: .ERR #ERRARE,#LNG,LEVEL=F,RETURN=YES ; INCB GOODLN ; Bad length - Set flag ;- ; Return to caller 60$: RETURN .DSABL LSB .SBTTL CMPSTR - Compare strings ;+ ; CMPSTR - This routine compares the string in UCL.DAT to the newly ; entered defined command string. ; ; This routine is called from: COMPAR ; ; This routine expects the following to already ; have been set up when entered: ; ; ARG1 -> Newly defined command ; ARG2 -> Current command from data base ; ; Upon exit, ; Carry - 0 - strings not equal ; 1 - strings equal ; ; This routine affects NO registers. ;- .ENABL LSB CMPSTR::MOV #ARGBLK,R5 ; R5 -> argument block PUSH R0 ; Save R0 PUSH R1 ; Save R1 PUSH R2 ; Save R2 PUSH R3 ; Save R3 PUSH R4 ; Save R4 PUSH R5 ; Save R5 CALL SCOMP ; Compare strings POP R5 ; Restore R5 POP R4 ; Restore R4 POP R3 ; Restore R3 POP R2 ; Restore R2 POP R1 ; Restore R1 POP R0 ; Restore R0 TST FLAG ; Same command? BEQ 10$ ; Yes, branch TST (PC)+ ; Skip next, clear carry 10$: SEC ; Set carry RETURN .DSABL LSB .SBTTL SHOCMD - Show commands ;+ ; SHOCMD - This routine outputs the commands in UCL.DAT with the appropriate ; definition in UCL.DAT. ; ; This routine is called from: GETLIN ; ; This routine does not expect anything to already ; have been set up when entered. ; ; This routine affects the contents of : R0 -> R5 ;- .ENABL LSB SHOCMD:: CLR R0 ; R0 = Channel number MOV SP,R1 ; Save stack .CSIGEN LIMT+2,#DEFEXT,#0,#OBUF ; Perform CSIGEN MOV R1,SP ; Restore stack MOV R0,BLKN1 ; Save new high limit TST OBUF ; Did the user type anything ? BNE 5$ ; Yes, proceed with display .PRINT #VERSON ; No, display version number RETURN ; TST (SP)+ ; Get dummy word off stack 5$: .WAIT #CHAN0 ; Channel 0 busy ? BCS 40$ ; Yes, branch MOV #ONE,R1 ; R1 = Channel number 10$: .WAIT R1 ; WAIT on channel BCC 40$ ; Branch if error INC R1 ; Increment pointer 20$: CMP #MAXCHN,R1 ; Processed all 8. channels ? BGE 10$ ; No, branch MOV BLKN1,R1 ; R1 = high address MOV R1,MYBUFF ; MYBUFF = address of buffer INC R1 ; R1 = 2nd spot of MYBUFF MOV R1,MYBUF2 ; MYBUF2 = 2nd spot of MYBUFF DEC R1 ; R1 = 1st spot of MYBUFF ADD #BYTBLK,R1 ; R1 -> new high address MOV R1,BLKN1 ; BLKN1 = start of BLKN1 buff MOV R1,MYEND ; MYEND = spot past out buffer CALL HOWBIG ; Find out size of data file CALL DEFSPC ; Go allocate buffer space CALL REOPEN ; Go open file CALL IEREAD ; Go read CALL SETNUM ; Setup # of d. c. in UCL.DAT CALL MOBKS ; Def. com bks yet to be read? CALL DEFCMD ; Setup # of d. c. in memory MOV MYBUFF,R0 ; R0 -> output buffer MOV #BYTBLK,R1 ; R1 = size of output buffer 30$: MOVB #SPACE,(R0)+ ; Blank fill output buffer SOB R1,30$ ; Branch if not done BR 50$ ; Skip error message ;+ ;ERROR 40$: .ERR #ERRARE,#INV,LEVEL=F.RETURN=NO ; Issue error message ; ;- 50$: MOV BLKN1,R1 ; R1 = start of buffer MOV TOTBLK,R2 ; R2 = # of blks. in buffer SWAB R2 ASL R2 ; Mult. by bytes / block ADD R1,R2 ; R2 -> Past end of buffer MOV R2,BLKEND ; BLKEND = Past end of buffer MOVB CMDBKS,DECMPR ; DECMPR = # of blks def. cmds ;+ ; NOW WE WANT TO SET UP THE VARIOUS POINTERS FOR THE DEFINED COMMAND BLOCKS ; AND THE DEFINITION BLOCKS ; IF ALL THE FILE IS IN MEMORY OR IF ALL THE BLOCKS OF DEFINED COMMANDS AND ; AT LEAST ONE BLOCK OF DEFINITIONS IS ALSO, THEN THE SETTING UP OF THE ; POINTERS WILL BE MUCH EASIER. ; IF NEITHER OF THESE CONDITIONS HOLDS TRUE, THEN A BLOCK OF DEFINTIONS ; WILL BE READ OVER THE LAST BLOCK OF DEFINED COMMANDS THAT WAS READ IN AND ; THE POINTERS WILL BE ADJUSTED ACCORDINGLY. ;- CMP TOTBLK,FSIZE ; Read in whole file ? BEQ 70$ ; Yes, branch CMPB CMDBKS,TOTBLK ; Any defintion blocks in mem? BLT 70$ ; Yes, branch ;+ ; THERE IS NOT A BLOCK OF DEFINTIONS IN MEMORY, SO THE FIRST BLOCK OF ; DEFINITONS MUST BE READ IN. IT WILL BE READ OVER THE LAST BLOCK OF ; DEFINED COMMANDS THAT WAS READ IN. ; FIRST, THE POINTERS MUST BE SET UP. ;- ; R2 = # OF DEFINED COMMAND BLOCKS READ MOV TOTBLK,R2 ; TAKE AWAY BLOCK THAT DEFINITIONS WILL BE READ OVER DEC R2 MOV R2,DECMPR ; Save value in DECMPR MOV R2,TOTBLK ; Save value in TOTBLK MOV R2,BLKNUM ; Save value in BLKNUM ; CALCULATE THE NUMBER OF WORDS OF DEFINED COMMANDS IN MEMORY SWAB R2 MOV R2,DEFCWD MOV R2,WDCNT ; Save value in WDCNT MOV DECMPR,R2 ; Reset value ; NOW CALCULATE THE BLOCK NUMBER THAT THE DEFINITIONS BEGIN AT IN UCL.DAT BIC #^C377,R1 ; Clear high byte MOVB CMDBKS,R1 ; R1 = # of blocks of def. cmd MOV R1,DEFBLK ; DEFBLK = block # of defs. ;+ ; NOW CALCULATE THE ADDRESS OF WHERE THE DEFINITIONS WILL BEGIN IN MEMORY ; R2 CONTAINS THE # OF BLOCKS OF DEFINED COMMANDS IN MEMORY ; MULTIPLY THIS BY # OF BYTES / BLOCK TO GET THE PROPER OFFSET TO WHERE ; THE DEFINITIONS BEGIN ;- SWAB R2 ; Mult. by 256. ASL R2 ; Mult. by # bytes / word MOV BLKN1,R1 ; R1 -> start of buffer ADD R1,R2 ; R2 -> start of defintions MOV R2,DEFADD ; Store value in DEFADD ; MOVE THE CORRECT NUMBER OF WORDS INTO DEFSCW MOV #WDSBLK,DEFSCW ; MOVE THE CORRECT NUMBER OF BLOCKS OF DEFINITIONS IN MEMORY TO DEFBKS MOV #ONE,DEFBKS ; NOW READ IN THE FIRST BLOCK OF DEFINITIONS .READW #EMTARE,#OUTCHN,DEFADD,DEFSCW,DEFBLK BCC 60$ ; Branch if no error ;+ ;ERROR .ERR #ERRARE,#INP,LEVEL=F,RETURN=NO ; ;- 60$: INCB MORBKS ; Set flag - more def. cmds. CALL DEFCMD ; Calculate # of def. cmds. BR 80$ ; Go process commands ;+ ; WE KNOW THAT THERE IS AT LEAST 1 BLOCK OF DEFINTIONS IS IN MEMORY. ; NOW SET UP THE POINTERS CORRECTLY. ; FIRST, CALCULATE THE NUMBER OF BLOCKS OF DEFINITIONS IN THE MEMORY ;- 70$: CLR R1 MOVB CMDBKS,R1 ; R1 = # of def. cmd. buf. bks SWAB R1 ; Mult. by 256. MOV R1,DEFCWD ; DEFCWD = # OF WORDS OF DEFINED COMMANDS IN MEMORY MOV TOTBLK,R1 ; R1 = # of bks. in buffer MOVB CMDBKS,R2 ; R2 = # of def. cmd. bks. SUB R2,R1 ; R1 = # of def. bks. in mem MOV R1,DEFBKS ; Store value in DEFBKS ;+ ; NOW SET UP THE CORRECT NUMBER OF WORDS OF DEFINITIONS IN MEMORY ; R1 CONTAINS THE CORRECT NUMBER OF BLOCKS OF DEFINITIONS IN MEMORY ; MULTIPLY THIS BY # OF WORDS / BLOCK (256.) AND THE PRODUCT WILL BE ; THE CORRECT NUMBER OF WORDS OF DEFINITIONS IN MEMORY AT ONCE ;- SWAB R1 ; This multiplys R1 by 256. ;+ ; THE EFFECT IS HAVING MULTIPLIED BY 256., WHICH IS WHAT WAS SUPPOSED TO ; HAPPEN. STORE THE VALUE IN DEFSCW. ;- MOV R1,DEFSCW MOV R2,DEFBLK ; Store value in DEFBLK ;+ ; NOW CALCULATE THE ADDRESS OF THE START OF THE DEFINTIONS. ; THIS ADDRESS IS CALCULATED BY: BEGINNING OF BUFFER + (# OF BYTES / BLOCK * ; # OF BLOCKS OF DEFINED COMMANDS) ;- SWAB R2 ; Mult. by # words / block ASL R2 ; Mult. by # bytes / block MOV BLKN1,R1 ; R1 -> beginning of buffer ADD R1,R2 ; R2 = address of 1st def. MOV R2,DEFADD ; Store value in DEFADD ; NOW ITS TIME TO PROCESS THE MEMORY AND BUILD THE OUTPUT BUFFER. 80$: MOV MYBUFF,R4 ; R4 -> Output buffer MOV #HEAD,R3 ; R3 -> Header MOV #HEDLEN,R1 ; R1 = Length of header 90$: MOVB (R3)+,(R4)+ ; Move header to output buffer SOB R1,90$ ; Count char and loop if more MOV #CR,R3 ; R3 -> CR MOVB (R3)+,(R4)+ ; Move CR MOVB (R3)+,(R4)+ ; Move LF MOV #CR,R3 ; R3 -> CR MOVB (R3)+,(R4)+ ; Move CR MOVB (R3)+,(R4)+ ; Move LF CLR R5 ; R5 = # of commands processed MOV DEFADD,R1 ; R1 -> Definitions MOV BLKN1,R2 ; R2 -> Commands ADD #SIZ,R2 ; R2 -> 1st spot for def. cmd. 100$: CALL PCMD ; Go process command INC R5 ; Count command processed CMPB (R2),#SPACE ; Was there a defined command? BEQ 110$ ; No, branch INC CMDCNT ; Count command 110$: CLR R3 ; Use R3 as temp word MOV #SIZ,R3 ; R3 = size of defined cmd. ADD R3,R2 ; R2 -> Next defined command MOV #CMDSIZ,R3 ; R3 = size of definition ADD R3,R1 ; R1 -> Next definition CMP R5,MAXNUM ; Proces. all def cmds in mem? BLT 120$ ; No, branch TSTB MORBKS ; More blks of defined cmds ? BEQ 140$ ; No, branch ;+ ; NOW READ IN MORE DEFINED COMMANDS ; NOW MOVE THE ACTUAL NUMBER OF WORDS OF DEFINED COMMANDS THAT CAN BE READ ; IN WITH ONE READ ;- MOV DEFCWD,WDCNT ; NOW EVERYTHING HAS BEEN SET UP, GO PERFORM THE READ PUSH R1 ; Save value on stack CALL IEREAD ; Go read CALL MOBKS ; Def. com bks yet to be read? CALL DEFCMD ; Setup # of d. c. in memory POP R1 ; Restore value CLR R5 ; R5 = # of cmds processed MOV BLKN1,R2 ; R2 -> 1st defined command ; NOW CHECK IF MORE DEFINITIONS MUST BE READ IN 120$: CMP R1,BLKEND ; Past end of buffer ? BLT 100$ ; No, branch ;+ ; MORE DEFINITIONS MUST BE READ IN ; SET UP THE CORRECT BLOCK NUMBER FROM UCL.DAT TO READ IN ; R3 = 1st BLK. OF DEFS READ LAST ;- MOV DEFBLK,R3 ADD DEFBKS,R3 ; R3 = blk to start read from MOV R3,DEFBLK ; DEFBLK = correct block # ; NOW THE POINTER HAVE BEEN SET UP, NOW PERFORM THE READ .READW #EMTARE,#OUTCHN,DEFADD,DEFSCW,DEFBLK BCC 130$ ; Branch if no error ;+ ;ERROR .ERR #ERRARE,#INP,LEVEL=F,RETURN=NO ; ;- 130$: MOV DEFADD,R1 ; R1 -> 1st definition BR 100$ ; Go process command 140$: TST CMDCNT ; Any commands to output ? BNE 150$ ; Yes, branch ;+ ;ERROR .ERR #ERRARE,#NCA,LEVEL=W,RETURN=NO,FILE=#FSPEC ;- 150$: MOV MYBUFF,R3 ; R3 = Beg. of output buffer CMP R3,R4 ; Anything to output ? BEQ 160$ ; No, branch MOVB #SPACE,(R4)+ ; Blank out last byte SUB R3,R4 ; R4 = # bytes to output ASR R4 ; R4 = # of words to output MOV R4,SWDCNT ; SWDCNT = # of words output CALL SWRITE 160$: RETURN .DSABL LSB .SBTTL PCMD Print command ;+ ; PCMD - This routine outputs a defined command and calls PKMO to output ; the correct defintion. ; ; This routine is called from: SHOCMD ; ; This routine expects the following to already ; have been set up when entered: ; ; R2 -> Current command in data base ; ; This routine affects the contents of : R2 -> R4 ;- .ENABL LSB PCMD:: ; RETURN if there is nothing to do CMPB (R2),#SPACE ; Anything to print? BEQ 100$ ; No, Return to caller ; Move six blanks to output buffer to indent display line MOV #SIX,R3 ; R3 = Counter for blanks 10$: CHROUT #SPACE ; Move " " to output buffer SOB R3, 10$ ; Repeat for count ; Move the command to the output buffer PUSH R2 ; Save R2 temporarily MOV R2,R3 ; R3 -> Command MOV #SIZ,R2 ; R1 = No. of characters 30$: CHROUT (R3)+ ; Move char to output buffer SOB R2,30$ ; Count char and loop if more ; Now move the " :== " MOV #SEPSTR,R3 ; Point to separator string MOV #FIVE,R2 ; Length of separator 40$: CHROUT (R3)+ ; Move char to output buffer SOB R2,40$ ; Count char and loop if more POP R2 ; Restore R2 ; Print the KMON definition on the same line 90$: CALL PKMO ; Print the KMON part 100$: RETURN .DSABL LSB .SBTTL PKMO Print KMON command ;+ ; PKMO - This routine outputs the correct definition of the current ; defined command in UCL.DAT to the output device specified. ; ; This routine is called from: PCMD ; ; This routine expects the following to already ; have been set up when entered: ; ; R1 -> KMON Command ; R2 -> UCL Command ; R4 -> Current position in output buffer ; R5 -> Counter for # of commands processed so far ; ; This routine affects the contents of : R3 -> R4 ;- .ENABL LSB PKMO:: PUSH R2 ; Save for return CLRB MCMDS ; Clear multiple commands flag ; + ; Move the KMON definition from the input buffer to the output buffer ; If a "177" is found, restore the backslash delimiter for multiple ; commands. Terminate the definition if a ' ' is found in the input ; buffer, indicating end of command definition, of if the max KMON ; command length is exceeded. ; - MOV R1,R3 ; R3 -> KMON command MOV #CMDSIZ,R2 ; Max. size of KMON command ; Replace internal command separator '177' with a backslash 10$: CMPB (R3),#177 ; Is char a "177" ? BNE 12$ ; No, branch MOVB #BSLASH,(R3) ; Replace it with a backslash INCB MCMDS ; Set multiple command flag BR 15$ ; Move it ; Terminate definition at double 'SPACE' 12$: CMPB (R3),#SPACE ; Is char a SPACE ? BNE 15$ ; No, move it CMPB 1(R3),#SPACE ; Is next char a SPACE ? BEQ 70$ ; Yes, end of definition ; Copy char to output buffer, PRINT buffer when it fills 15$: CHROUT (R3)+ ; Move char to output buffer SOB R2, 10$ ; Move chars up to max count ; End the output line with '\\' if we have multiple commands 70$: TSTB MCMDS ; Multiple commands on line ? BEQ 90$ ; No, branch CHROUT EMDMLT ; Move backslash to buffer CHROUT EMDMLT ; Move another backslash to buffer ; Now move CR and LF to the output buffer 90$: CHROUT CR ; Move CR to output buffer CHROUT LF ; Move LF to output buffer ; Return to caller POP R2 ; Restore UCL pointer RETURN .DSABL LSB .END UCL