.TITLE MCE - MCR-Command-Editor .IDENT /2.6/ .NLIST BEX .ENABLE LC .SBTTL MCE - Installation ; ; MCE - MCR Editor - see MCR.HLP ; ; First Idea: D. Sponza (YU) 06-OCT-81 ; Modifications: -tf- 18-Nov-81 ... Sep-82 ; ; Rolle / Paranor: VMS V4.0 compatibility introduced ; 20-Sep-84 ; 06-Mar-85 "PF2" as RECALL ; 29-Apr-85 Allow Translations with "*" ; ; Build with: ; MAC MCE=MCE ; TKB with following commandfile: ; MCE/CP=MCE ; LB:[1,1]VMLIB/LB:INIDM:EXTSK ; / ; TASK=...MCE ; ; Task Extension contains FIFO ans Translation Buffers ; ; increment it if necessary: ; EXTTSK=400 ; / ; ; Options: ; FILE=0 ; Define to get file support from MCEINI.CMD MAXFIF = 23. ; Maximal Number of entries in FIFO TMOTIM = 60. ; Timeout period. Timeout time is for logout is TMOTIM*TMO0 Mins TMO0 = 4 ; see above .SBTTL Help Text to be extracted ;+ ; MCE - Utility Commands ; ; MCE V2.6 Supports all Line Editing Functions of VMS V4.0: ; ; - Switch between overstrike and insert mode ; or UP-ARROW - retrieve previous command ; DOWN-ARROW - reverse of UP-ARROW (next command) ; or LEFT-ARROW - Move Cursur left ; - Go to end of line ; or RIGHT-ARR - Move Cursur right ; or BACKSPACE - Move Cursur to beginning of line ; or LINEFEED - delete word to the left of the cursur ; - delete from beginning of line to cursor ; ; Additional Features: ; - Translate command without execution ; - Recall Command previously requester starting ; with a string entered before pressing key ; - Show Command Translation Buffer ; - Display previously requested commands (similar ; VMS RECALL/ALL command, in reversed order) ; ; Exit MCE with "BYE" or "EXIT" command. ; ; See HELP MCE TRANS for Command Translation ; RECALL for recalling Commands from Queue ;2 TRANS ; As in DCL from VMS a command may be defined by: ; > CNAM := ; where CNAM is the command name which will be substituted by the ; text at the right side of the ":=". ; NOTE: The ":=" must be prececed and followed by a single space. ; e.g.: > HE := HELP MCE ! followed by space, to append further text ; > HE ! will request "HELP MCE" ; ; The translation may be performed without execution by (only ; displayed on terminal ; ; If you enter a predefined command followed by additional text, ; this additional text will normally be appended as whole. ; e.g.: > HE TRAN ! will request "HELP MCE TRAN" ; or: > HE TRAN ; will be translated and displayed: ; result > HELP MCE TRAN ; ; You may delete a command translation entry by redefining it to null. ; e.g.: > HE := ! delete above definition ; ; It is also possible to allow abbreviations of commands (as in DCL) ; by separating the optional part by "*". ; e.g.: > HM*CE := HELP MCE ; This command may now be requested with: ; > HM or HMC or HMCE or HMCEXXX etc. ; ; More sophisticated substitution is possible by the Parameter-Substitution, ; similar to the indirect commandfile processor. ; e.g.: > DIR*ECTORY := PIP 'P1'/LI ; > COP*Y := PIP 'P2'/NV/CD='P1' ; > DIR ! will be translated into "PIP /LI" ; > DIREC FIL ! will be translated into "PIP FIL/LI" ; > COPY A.CMD [200,200] ! will simulate DCL COPY command ; ; You may request a command with function keys , , or ; by definining the command translation "PFn := command". ; e.g. > PF2 := TIM ! redefine HELP function key ; ! to display the current time ; ; Note that Command Definitions may be performed from the commandfiles ; SY:[1,2]MCEINI.CMD, followed by ; SY:MCEINI.CMD ; which will always be read when starting MCE ;2 RECALL ; Recalling command is done by entering the first part of a command ; which was previously executed, termimated by the function key "PF2". ; This will find the last commands already executed starting with the ; string entered. The command may be edited or executed by pressing ; the return key. ; Note that the function key "PF2" may not have any superimposed ; translation defined (by defining "PF2 := ..."). ; ; Example: ; > DIR X.DAT ! Previously entered commands ; > DMP X.DAT ; > .. ; > D ! will recall the first command ; > DMP X.DAT ! starting with "D" ; > DI ! will recall the command: ; > DIR X.DAT ;- .SBTTL MCE - Macros, Konstanten, Variablen .MCALL QIO$S,EXIT$S,SPWN$S,STSE$S .MCALL MRKT$S,ASTX$S,GLUN$S BUFSIZ=76. ; (this is max for >SET /BUF=TI:80.) BELL=7 BKSP=10 LF=12 CR=15 ESC=33 BLNK=40 ; .IF DF,FILE .PSECT $$FSR0 ; start of region to be released FSR0: .MCALL FSRSZ$, FDBDF$, FDRC$A, FDOP$A, OPEN$R, GET$S, CLOSE$ FSRSZ$ 1 .PSECT $$FSR0 .ENABL LSB FDBIN: FDBDF$ ;FDB for initialization FDRC$A ,NEW,BUFSIZ FDOP$A 1, 10$,, FO.RD 1$: .ASCII /SY:/ ;Device Name DEVL = .-1$ 2$: .ASCII /[1,2]/ ;Directory DIRL = .-2$ 3$: .ASCII /MCEINI.CMD/ ;File name NAML = .-3$ .EVEN 10$: .WORD DEVL,1$ ; File Descriptor: Device FDIRL: .WORD DIRL,2$ ; directory string (initially on above Dir) .WORD NAML,3$ ; File name .DSABL LSB .PSECT .ENDC ; ; Text Formats ; HELPT: .ASCIZ \MCE - MCR-Editor V 2.6\ ADTEXT: .ASCIZ \MCE - Exit\ NOPOOL: .ASCIZ /MCE - Pool exhausted - Install MCE with INC/ TOOLON: .ASCIZ /MCE - Command too long/ ;HLPTXT: .ASCIZ /HELP MCE/ BYETXT: .ASCIZ /Bye/ EXITXT: .ASCIZ /Exit/ ; PROMLF: .ASCII ; Prompt Buffer with new line PROMPT: .ASCII \> \ ; without new line NEW: .REPT BUFSIZ+4 ; current Buffer .ASCII ; must be blanked .ENDR ; .EVEN SAVB: .BLKB BUFSIZ+4 ; Save Buffer (start on even boundary) BS: .REPT BUFSIZ+2 ; Backspace buffer for .ASCII ; Cursor positioning .ENDR ; .EVEN ; ; FIFO Buffer ; ; Entry offsets : ;FNXT = 0 ; Pointer to next Entry FLEN = 2 ; Length of entry FTXT = 4 ; Text, terminated by binary 0 FIFO: .WORD 0, FIFO ; Header FIFO Buffer: FIFCNT: .WORD 0 ; Number of entries in FIFO FIFPTR: .WORD 0 ; Ptr to current Entry (for UP, DOWN keys) ; ; Commandbuffer, same entries as in FIFO ; CMDB: .WORD 0, CMDB ; Header ; FREE: .WORD 0,0 ; Free memory listhead ; IOSTAT: .BLKW 2 TASK: .RAD50 \MCR...\ ; CODE: .WORD 0 ; QIO-Functioncode ADR: .WORD 0 ; BUFFER-ADRESS LEN: .WORD 0 ; BUFFER-LENGH (TO OUTPUT) CHAR: .WORD 0 ; INPUT-CHARACTER ; ; Modes (NE if set) OVSTMO: .BYTE 0 ; If overstrike mode EXITFL: .BYTE 0 ; Exit if NE FILINP: .BYTE 0 ; if File Input NOLOAD: .BYTE 0 ; Skip loading of Command in Commandbuffer ANSII: .BYTE 0 ; If Ansii Terminal for delete Line Escseq TTN: .BYTE 0 ; Terminal Number TMOCNT: .BYTE TMO0 ; Counter for timeout .EVEN ; .SBTTL MCE - Sprungtabelle ; ;JUMP TABLE FOR MRC COMMANDS ; TAB: .WORD INSERT ; SINGLE CHR. .WORD chover ; CTRL/A .WORD ctrlb ; CTRL/B .WORD loop ; CTRL/C .WORD BACKSP ; CTRL/D .WORD ENDLIN ; CTRL/E .WORD skip ; CTRL/F .WORD loop ; CTRL/G .WORD BEGLIN ; BS (CTRL/H) .WORD inser0 ; HT (CTRL/I) .WORD DELEW ; LF (CTRL/J) .WORD LOOP ; CTRL/K .WORD loop ; CTRL/L .WORD EXEC ; CR (CTRL/M) .WORD loop ; CTRL/N .WORD loop ; CTRL/O (STOP OUTPUT TO TI:) .WORD loop ; CTRL/P .WORD loop ; CTRL/Q (XON) .WORD ctrlr ; CTRL/R .WORD loop ; CTRL/S (XOFF) .WORD loop ; CTRL/T .WORD CTRLU ; CTRL/U .WORD loop ; CTRL/V .WORD loop ; CTRL/W .WORD loop ; CTRL/X .WORD loop ; CTRL/Y .WORD loop ; CTRL/Z .WORD ESCAP ; ESC .WORD loop ; CTRL/\ .WORD loop ; CTRL/] .WORD loop ; ( CTRL/^ , VT100 does not send this char) .WORD DELEC ; DEL ; ; ; Gebrauch der Register: ; ; R0 Scratch Pointer ; R1 Cursor in NEW ; R2 First free byte in NEW (End of Text) ; R3 Result of READNR ; R4 Scratch ; R5 Scratch Counter ; ; .SBTTL MCE - I/O and other subroutines ; ; SUBROUTINES FOR ALL DIFERENT KINDS OF I/O ; ; print CR ; IOCR: MOV #IO.WVB,CODE ; PRINT MOV #PROMPT,ADR MOV #1,LEN ; go to IO ; ; QIO routine ; IO: MOVB #TMO0, TMOCNT ; set new timeout QIO$S CODE,#5,#5,,#IOSTAT,, STSE$S #5 RTS PC ; ; Write from current Position to End of Line and reposition Cursor ; UPD1: MOV #IO.WVB,CODE MOV R1,ADR ; CURSOR MOV R2,LEN SUB R1,LEN BEQ 1$ CALL IO ; WRITE REST OF LINE MOV #BS,ADR CALL IO ; CURSOR BACK 1$: RETURN ; ; Rewrite whole Line ; DISPLY: ; RETYPE EDIT-BUFFER TSTB ANSII ; Ansii Screen ? BNE 3$ ; Y CMP ADR, #PROMLF ; N- just new Line written ? BNE 2$ ; N- start new line CMP LEN, #2 ; something written ? BLE 3$ ; N- do not start new Line 2$: MOV #PROMLF, ADR ; Y- skip LF BR 4$ 3$: MOV #PROMPT,ADR 4$: MOV R2,LEN ; calculate length SUB ADR, LEN MOV R0, -(SP) ; set up to delete to EOL MOV R2, R0 MOVB #ESC, (R0)+ ; delete to EOL MOVB #'[, (R0)+ MOVB #'K, (R0)+ TSTB ANSII ; Ansii Screen ? BEQ 5$ ; N ADD #3, LEN ; Y- make Escseq visible 5$: MOV #IO.WVB,CODE CALL IO MOVB #40, -(R0) ; restore escseq MOVB #40, -(R0) MOVB #40, -(R0) MOV (SP)+, R0 MOV #BS,ADR MOV R2,LEN SUB R1,LEN BEQ 1$ CALL IO ; write same no of backspaces 1$: RETURN ; ; Load Buffer into NEW, R0 points to source ; GETBUF: MOV #NEW,R1 ; ADR. OF THE NEW->R1 MOV R1, R2 MOV #BUFSIZ,R5 ; BUF. LENGTH->R5 1$: MOVB (R0)+,(R1)+ ; NEW <-- BUF BEQ 3$ CMPB -1(R1),#BLNK ; BLANK ? BEQ 2$ MOV R1,R2 ; POINT BEHIND LAST 2$: SOB R5, 1$ ; GO BACK IF NOT THE END BR 4$ 3$: MOVB #BLNK,-1(R1) ; OVERPRINT 000 (.ASCIZ) 4$: MOV R2,R1 ; BOTH AT THE END RETURN ; ; Print Message ; IOMSG: ; Print a Msg in (R0) CALL IOCR CALL GETBUF CALL DISPLY ; ; Clear Buffer NEW ; CLRNEW: MOV #NEW,R1 ; ADR. OF THE NEW->R1 MOV #BUFSIZ,R5 ; BUF. LENGTH->R5 1$: MOVB #BLNK,(R1)+ ; RESET NEW TO BLANK SOB R5, 1$ ; GO BACK IF NOT THE END MOV #NEW,R1 ; ADR. OF THE NEW->R1 MOV R1,R2 ; NEW IST EMPTY RETURN .IF DF,FILE .SBTTL MCE - reading MCEINI.CMD .PSECT $$FSR9 ; to be released after initial TCH: .BYTE TC.TTP,0 ; FILOP: ; Open File MOV #TCH, ADR ; first find out if its a ANSII Terminal MOV #2, LEN MOV #SF.GMC, CODE CALL IO MOVB TCH+1, R0 ; Get Terminal Type BEQ 2$ ; unknown ; CMPB R0, #T.Vxxx ; VTxxx ? ; BEQ 1$ ; Y CMPB R0, #T.V100 ; VT100 ? BNE 2$ ; N 1$: DECB ANSII ; set Ansii Terminal 2$: MOV #NEW+1&^C1, R0 ; temporary buffer, word aligned GLUN$S #5, R0 ; Get terminal number MOVB 2(R0), TTN ; and save it .IF DF, TMOTIM MRKT$S ,#TMOTIM,#2,#TIMAST ; Marktime for timeout .ENDC CALL FILO1 ; Open File on [1,2] BCC RET0 ; success CLR FDIRL ; no success - try to open second file FILO1: CLRB FILINP ; ASSUME FILE can not by opened OPEN$R #FDBIN ;OPEN INPUT FILE BCS RET0 DECB FILINP ; enable File Input RET0: RETURN ; RETURN WITH CC-C FILREA: GET$S #FDBIN ;GET A RECORD FROM INFILE BCS FILCLO ; no more records MOV F.NRBD(R0), R2 ; this length BLE FILREA ; empty line MOV R2, LEN ; store TST (SP)+ ; do not return JMP EXEC0 ; but execute directly FILCLO: CLRB FILINP CLOSE$ #FDBIN ; CLOSE INPUTFILE TST FDIRL ; Already on default directory ? BEQ 2$ ; Y CLR FDIRL ; N- Open MCEINI.CMD for default dir CALL FILO1 ; if there BCC FILREA ; READ NEXT INPUT LINE from there 2$: MOV #FSR0+3, R2 ; Start Addr to be released BIC #3, R2 ; align it MOV #10$-3, R1 ; end of region SUB R2, R1 ; length MOV #FREE, R0 JMP $RLCB ; put this region to Free list 10$: ; and return directly from there .PSECT .IF DF,TMOTIM ; On timeout - log off (TT0: just exit) TIMAST: TST (SP)+ ; restore stack DECB TMOCNT ; timeout ? BLT 15$ ; should not have decremented BNE 20$ ; not yet ; timed out - kill pending read MOV #IO.KIL, CODE ; Kill pending read CALL IO 15$: CLRB TMOCNT 20$: MRKT$S ,#TMOTIM,#3,#TIMAST ; next Marktime ASTX$S .ENDC .ENDC .SBTTL MCE - INIT-Code, Main-Loop ; START: ; CALL IOCR MOV #FREE, R0 CALL $INIDM ; Initialize Free Memory .IIF DF,FILE CALL FILOP ; INGOON: MOV #HELPT, R0 CALL IOMSG ; ; Get next Line ; RESTAR: .IF DF,FILE TSTB FILINP ; File Input ? BEQ 10$ ; N CALL FILREA ; Y- goto EXEC0 if something read 10$: .ENDC CALL CLRNEW MOV #IO.ATT,CODE ; ATTACH THE TERMINAL CALL IO MOV #IO.WVB,CODE ; PRINTING OF THE PROMPT MOV #PROMLF,ADR MOV #4,LEN CALL IO ; ; Accept next Character for input and dispatch it ; LOOP: MOV #IO.RST!IO.RNE,CODE ; ACCEPT ONE CHR. MOV #CHAR,ADR ; EXTRABUFFER !! MOV #1,LEN CALL IO ; READ 1 CHAR CMPB IOSTAT, #IE.ABO ; IO killed ? BNE 20$ ; N MOV #BYETXT, R0 ; Y- get last command TSTB TTN ; are we on TT0: ? BNE 16$ ; N- Spawn BYE MOV #EXITXT, R0 ; Y- exit 16$: CALL GETBUF CALL DISPLY DECB EXITFL ; make sure to Exit JMP EXEC ; execute BYE or EXIT command 20$: MOVB IOSTAT+1,R4 ; TEST FOR BRANCH TABLE BIC #177740,R4 ; IO.RST GIBT ALLE CTRL-CHAR IN IOSTAT ASL R4 JMP @TAB(R4) ; <== DISPATCH .SBTTL MCE - Edit-commands ; ; INSERT ONE CHARACTER ; INSER0: MOVB #40, CHAR ; insert space (e.g. instead of tab) INSERT: CMP R2,#NEW+BUFSIZ ; NOCH PLATZ ? BLO 3$ JMP CURERR 3$: MOV #IO.WVB,CODE MOV #CHAR,ADR ; ECHO MOV #1,LEN CALL IO BITB #1, OVSTMO ; overstrike ? BEQ 10$ ; N MOVB CHAR,(R1)+ ; overstrike CMP R1, R2 ; at end ? BLOS 12$ ; N MOV R1, R2 ; Y- increment end ptr BR 12$ 10$: INC R2 ; no overstrike - shift MOV R2,R0 1$: MOVB -(R0),1(R0) ; SHIFT STRING CMP R0,R1 BHI 1$ MOVB CHAR,(R1)+ ; INSERT NEW CHARACTER CALL UPD1 12$: LOOP1: BR LOOP ; ; CURSOR RIGHT ; SKIP: CMP R1,R2 ; END OF TEXT ? BHIS CURERR MOV #IO.WVB,CODE ; PRINT CHR. MOV R1,ADR ; CURSOR POSITION MOV #1,LEN CALL IO INC R1 ; SHIFT CURSOR BR LOOP1 ; ; CURSOR LEFT ; BACKSP: CMP R1,#NEW ; THE BEGINING OF THE BUF. BLOS CURERR MOV #IO.WVB,CODE ; GO ONE CHR. BACK MOV #BS,ADR MOV #1,LEN CALL IO DEC R1 ; CURSOR CURERR: BR LOOP1 ; ; BEGIN OF LINE ; BEGLIN: MOV #IO.WVB,CODE MOV #PROMPT,ADR MOV #3,LEN ; REPOSITION CURSOR CALL IO MOV #NEW,R1 1$: BR LOOP1 ; ; DELETE LEFT SINGLE CHAR ; DELEC: CMP R1,#NEW ; TEST LIMIT BLOS 100$ DEC R1 ; CURSOR MOV #IO.WVB,CODE ; CURSOR ONE CHR. BACK MOV #BS,ADR MOV #1,LEN CALL IO MOV R1,R0 1$: MOVB 1(R0),(R0)+ ; SHIFT STRING LEFT CMP R0,R2 BLOS 1$ CALL UPD1 DEC R2 ; END OF TEXT 100$: LOOP2: BR LOOP1 ; ; DELETE LEFT SINGLE WORD ; DELEW: CMP R1,#NEW ; TEST LIMIT BLOS 100$ MOV #IO.WVB,CODE MOV R1, -(SP) ; save initial Pointer 10$: DEC R1 ; CURSOR CMP R1, #NEW ; at beginning of line ? BLOS 12$ ; Y MOVB -1(R1), R0 ; N- get previous char CMPB R0, #40 ; space BNE 11$ ; N CMPB R0, (R1) ; Y- was previous one a space ? BEQ 10$ ; Y- then delete it 11$: CMPB R0, #'0 ; alphabetical ? BLO 12$ ; certainly not CMPB R0, #'9 ; really ? BLO 10$ ; Y CMPB R0, #'_ ; special char ? BEQ 10$ ; Y- accept BIC #40, R0 ; convert to upper CMPB R0, #'A ; alphabetical ? BLO 12$ ; N CMPB R0, #'Z ; maybe - check upper limt BLOS 10$ ; ok - alphabetical 12$: MOV (SP)+, R0 ; restore initial pointer MOV R1, -(SP) 20$: CMP R0,R2 ; more to shift BHIS 25$ ; N MOVB (R0), (R1)+ ; shift down MOVB #40, (R0)+ ; must be replaced by space BR 20$ 25$: MOV R1, R2 ; new end ptr MOV (SP)+, R1 ; restore CTRLR = . CALL DISPLY ; write buffer 100$: BR LOOP2 ; ; Delete from start of line to cursor ; CTRLU: CMP R1,#NEW BLOS 1$ ; FERTIG MOV #NEW,R0 2$: CMP R1,R2 BEQ 5$ MOVB (R1)+,(R0)+ ; SHIFT STRING LEFT BR 2$ 5$: MOV R0,R2 ; END OF TEXT 4$: CMP R0,#NEW+BUFSIZ BHIS 3$ MOVB #BLNK,(R0)+ ; FILL WITH BLANK BR 4$ ; 3$: MOV #IO.WVB,CODE MOV #PROMPT,ADR MOV R1,LEN SUB #PROMPT,LEN CALL IO MOV #3,LEN ; REPOSITION CURSOR CALL IO MOV #NEW,R1 1$: BR LOOP2 ; ; JUMP TO END OF TEXT ; ENDLIN: MOV #IO.WVB,CODE MOV R1,ADR MOV R2,LEN SUB R1,LEN BEQ 1$ CALL IO MOV R2,R1 ; END OF TEXT 1$: BR LOOP2 ; ; Flip between insert and overstrike mode ; chover: INCB OVSTMO ; change overstrike mode BR LOOP2 .SBTTL MCE - Escape Sequences / FIFO - Commands ; ESCAP: CALL IO ; read next char MOVB CHAR, R0 ; get it here CMPB R0,#'[ ; VT100 or VT52 BEQ ESCAP CMPB R0,#'O ; VT100 BEQ ESCAP CMPB IOSTAT+1,#ESC ; esc/esc BEQ ENDLIN CMPB R0,#'A ; ^ BNE 5$ CTRLB = . ; Take older command MOV FIFPTR, R5 ; get Ptr of buffer BNE 51$ ; defined TST FIFO ; any entry at all ? BEQ 12$ ; N MOV FIFO+2, FIFPTR ; Y- take newest entry BR 12$ 51$: MOV #FIFO, R5 ; N- find previous entry 53$: MOV (R5), R5 ; next BEQ 12$ ; No more CMP (R5), FIFPTR ; does this point to me ? BNE 53$ ; not this MOV R5, FIFPTR ; found - load and BR 12$ ; display ; 5$: CMPB R0,#'B ; v - find newer command BNE 6$ MOV FIFPTR, R5 ; CTRLB already called ? BEQ 12$ ; N MOV (R5), FIFPTR ; next 12$: CALL GEFIFO ; Load NEW from FIFO BR LOOP0 ; 6$: CMPB R0,#'C ; --> BNE 2$ JMP SKIP ; Skip single char ; 2$: CMPB R0,#'D ; <-- BNE 7$ JMP BACKSP ; Backspace on char ; 7$: SUB #'P-1, R0 ; any PFn ? BLE LOOP0 ; N CMP R0, #4 BHI LOOP0 ; N MOV R0, -(SP) ; Y- save 1,..,4 for ,.. MOV #"PF, SAVB ; check if to be translated ADD #'0, R0 MOV R0, SAVB+2 MOV #3, PDSC ; set up P0 MOV #SAVB, PDSC+2 MOV R2, -(SP) CALL FNDCMD ; find cmd MOV (SP)+, R2 MOV (SP)+, R0 BCS 46$ ; no entry found MOV R1, R0 ; find start of text 40$: ; execute command in (R0) CALL IOCR ; clear current line CALL GETBUF ; load new buffer SUB #NEW, R2 ; calculate length MOV R2, LEN ; save it MOV #IO.DET,CODE ; DEATT. THE TERMINAL CALL IO JMP EXEC1 ; and execute without display 46$: ; execute function key MOV R2, R1 ; point to end of buffer ASL R0 ; word offset ADD R0, PC ; branch NOP BR 41$ ; BR 42$ ; BR 43$ ; ; PRINT WHOLE FIFO CALL PRIFIF BR LOOP0 41$: ; Translate CMP R2, #NEW ; something in buffer BEQ LOOP0 ; N- ignore command DECB NOLOAD ; disable command load SUB #NEW, R2 ; calculate Length MOV R2, LEN ; store CALL CMDCHK ; command Translation MOV LEN, R2 ; restore R2 ADD #NEW, R2 ; point to end MOV R2, R1 CALL DISPLY CLRB NOLOAD ; enable command load BR LOOP0 42$: ; - RECALL CALL RECCMD ; Recall Command BR LOOP0 43$: ; Print CMD Buffer CALL PRICMD ; BR LOOP0 LOOP0: JMP LOOP .SBTTL FIFO Buffer Subroutines ; ; FIFO OPERATIONS ; ; Get FIFO Buffer, pointet to by FIFPTR ; GEFIFO: MOV FIFPTR, R0 ; get Ptr BNE 10$ ; defined MOV #FIFPTR, R0 ; Null String BR 12$ 10$: ADD #FTXT, R0 ; get start of text 12$: CALL GETBUF ; load buffer CALL DISPLY RETURN ; ; Print FIFO / or Command buffer and put pointer to end of queue ; .ENABL LSB PRIFIF: MOV #FIFO, FIFPTR BR 4$ PRICMD: MOV #CMDB, FIFPTR 4$: MOV #IO.WVB, CODE 5$: MOV #PROMLF,ADR ; print LF MOV #1,LEN CALL IO MOV @FIFPTR, FIFPTR ; next PTR BEQ 10$ ; all done CALL GEFIFO ; display BR 5$ 10$: CALL CLRNEW ; clear line, FIFPTR already cleared CALL DISPLY RETURN .DSABL LSB ; ; Clear first entry of FIFO buffer ; CLFIF: MOV #FIFO, R0 ; this header CALL FRENT BCS 10$ DEC FIFCNT ; adjust count 10$: RETURN ; ; Free entry from queue (Header in R0). CC-C set if it was empty ; FRENT: JSR R5, .SAVR1 ; save Regs MOV (R0), R2 ; get entry if any SEC BEQ 10$ ; none MOV (R2), (R0) ; remove from head of queue BNE 2$ ; more entries MOV R0, 2(R0) ; this was last one 2$: MOV FLEN(R2), R1 ; this length MOV #FREE, R0 CALL $RLCB CLC 10$: RETURN ; ; Load NEW into FIFO Buffer ; Input: R2 - Length LDFIF: JSR R5, .SAVR1 ; save Regs CLR FIFPTR ; initialize FIFO Ptr MOV R2, R5 ; Length BEQ 10$ ; None MOV R5, R1 ; save it ADD #FTXT+2, R1 ; increment for header CMP FIFCNT, #MAXFIF ; Maximum reached ? BLO 2$ ; N 1$: CALL CLFIF ; release one entry BCS 10$ ; nothing to release 2$: MOV #FREE, R0 CALL $RQCB ; request core block BCS 1$ ; nothing received yet - release more CLR (R0) ; no next entry MOV R0, @FIFO+2 ; link to previous MOV R0, FIFO+2 ; new last entry MOV R1, FLEN(R0) ; total length ADD #FTXT, R0 ; MOV #NEW, R1 ; Source text 4$: MOVB (R1)+, (R0)+ ; load SOB R5, 4$ CLRB (R0) ; End of string INC FIFCNT ; count 10$: RETURN .SBTTL MCE - Execute new Command ; .ENABL LSB EXEC: CALL IOCR MOV #IO.DET,CODE ; DEATT. THE TERMINAL CALL IO ; SUB #NEW, R2 ; calculate Length MOV R2, LEN ; store BLE 1$ ; CALL LDFIF ; Load into FIFO EXEC0: CALL CMDCHK ; Check for command Translation BCS 1$ ; nothing to execute EXEC1: CLRB TMOCNT ; disable timeouts (until next IO) SPWN$S #TASK,,,,,#1,,,#NEW,LEN ; EXECUTE MCR COMMAND ; TSTB EXITFL BNE EXIT STSE$S #1 ; STOP UNTIL THE MCR RETURN COMMAND 1$: JMP RESTAR .DSABL LSB ; ; Exit ; CTRLZ: EXIT: MOV #ADTEXT,R0 CALL IOMSG MOV #IO.DET,CODE ; DEATT. THE TERMINAL CALL IO EXIT$S ; Exit .SBTTL Command Substitution etc. CDSC: .WORD 0,0 ; descriptor of whole remainder PDSC: ; descriptor of P0 .. P8 .REPT 9. .WORD 0,0 .ENDR CFETCH: .BYTE 0 ; Flag if Paramter fetched OVMSG: .BYTE 0 ; Send Overflow Message CTSTAR: .BYTE 0 ; Find command with "*" enabled (ne 0) TMPFLG: .BYTE 0 ; Temporary Flag: "*" encountered in compare .EVEN CLL = .-CDSC ; region to be cleared from CDSC ; ; FNDCMD - Find entry in Command (=Translation-) Table ; FNDCMA - Find entry in Command (=Translation-) Table - accept Abbreviations ; ; Input - PDSC of P0 defined ; - CTSTAR .ne.0 to allow abreviated command if command ; definition contains "*" (a la VMS) ; Output - CC-C set - no entry found ; CC-C clr - entry found ; R0 - to entry ; R1 - to point to string after ":=" ; R2 - to previous entry (for remove and inserts) ; .ENABL LSB FNDCMA: MOVB #1, CTSTAR ; enable abbreviations BR 2$ FNDCMD: CLRB CTSTAR ; ignore "*" in translation buffer 2$: MOV #CMDB, R0 ; Header MOV R3, -(SP) CLR -(SP) ; for previous entry 10$: MOV R0, (SP) ; Save previous entry TST (R0) ; any next entry ? BEQ 29$ ; N- end of list MOV (R0), R0 ; Y- take next entry MOV R0, R1 ; to Text ADD #FTXT, R1 MOV PDSC, R3 ; length to be compared BLE 29$ ; ? MOV PDSC+2, R2 ; and start addr of P0 TSTB CTSTAR ; without abbreviation ? BEQ 27$ ; Y- exact match required ; Check for match, accepting any "*" in command defintion CLRB TMPFLG ; Reset Flag: "*" found in Cmd Translation 13$: CMPB (R1), #'* ; check for "*" in translation buffer BNE 15$ ; not yet found INCB TMPFLG ; Y- found, remember it INC R1 ; to next char 15$: CMPB (R1), #40 ; end of translation buffer ? BEQ 17$ ; Y- terminate compare CMPB (R2)+, (R1)+ ; check for equality BEQ 16$ ; match BGT 10$ ; NE and must come further down in list TSTB TMPFLG ; passed entry - any "*" seen ? BNE 10$ ; then continue search BR 29$ ; else we passed alphabetical order 16$: SOB R3, 13$ ; match- to next char CMPB (R1), #40 ; end of input string - translation buffer BEQ 20$ ; is also terminated CMPB (R1), #'* ; or next byte might be end ? BEQ 20$ ; Y- then accept 17$: TSTB TMPFLG ; match found- abbreviation possible ? BEQ 10$ ; N- then don't accept match- to next entry 20$: CMPB (R1)+, #40 ; goto end of string (or binary 0???) BHI 20$ ; not yet found BR 28$ ; point past key ; Check for match, igoring any "*" in command defintion 27$: CMPB (R2)+, (R1)+ ; compare BGT 10$ ; NE and must come further down in list BLT 29$ ; already passed alphabetical order SOB R3, 27$ CMPB (R1)+, #40 ; match - followed by space ? BNE 29$ ; no still continuing 28$: ADD #3, R1 ; skip ":= " CLC BR 30$ 29$: SEC 30$: MOV (SP)+, R2 ; to previous entry MOV (SP)+, R3 RETURN .DSABL LSB ; ; Check for Command definition ; or replace first command word by stuff defined in command buffer ; P1..P8 may also be replaced ; ; R2 - length of buffer in NEW (also stored in LEN) ; on return: LEN updated, all Regs destroyed CMDCHK: ; all Regs destroyed MOV #CDSC, R0 ; Clear scratch buffer MOV #CLL/2, R1 2$: CLR (R0)+ SOB R1, 2$ MOV #NEW, R1 ; Source Buffer MOV #SAVB, R3 ; Destination Buffer MOV #PDSC, R5 ; to current Para Desc MOV R3, 2(R5) ; start of P0 10$: ; Store single char MOVB (R1)+, R0 ; next char - convert to upper CALL CNVUPC ; check for delimiter MOVB R0, (R3)+ ; store char BCC 20$ ; no delimiter found CMP R5, #PDSC ; on P0 ? BNE 15$ ; N MOV R3, CDSC+2 ; load starting Addr 15$: ; to next Pn CMP R5, #8.*4+PDSC ; already on P8 ? BHIS 20$ ; Y- put it all there ADD #4, R5 ; N- to next Para MOV R3, 2(R5) ; starting address BR 25$ ; do not count 20$: ; no delimiter found INC (R5) ; count char 25$: SOB R2, 10$ MOV CDSC+2, R2 ; Remainder Descriptor defined ? BEQ 26$ ; N SUB R2, R3 ; Y- then calculate length of it MOV R3, CDSC ; and store ; ; Now everything is moved into SAVB ; Check if we define a new command ":=" in P1 26$: MOV #4+PDSC, R2 ; to P1 descr CMP (R2)+, #2 ; correct length ? BNE 28$ ; N MOV (R2), R2 ; Y- to string CMPB (R2)+, #': BNE 28$ CMPB (R2)+, #'= BNE 28$ JMP NEWCMD ; match found ; Try find an entry in the commandbuffer with key P0 28$: CALL FNDCMA ; check in table BCC 30$ ; entry found ; no entry found CMP PDSC, #4 ; "EXIT ?" BGT 29$ ; N BLT 281$ ; N CMP SAVB, #"EX ; length match BNE 29$ CMP SAVB+2, #"IT ; Exit ? BNE 29$ ; N JMP EXIT ; Y 281$: CMP PDSC, #3 ; did we receive "BYE" ? BNE 29$ ; false length CMP SAVB, #"BY ; ok ? BNE 29$ ; N CMPB SAVB+2, #'E BNE 29$ ; N DECB EXITFL ; Y- set exit Flag 29$: CLC ; execute BR 85$ 30$: ; entry found, R1 points to Text MOV #NEW, R2 ; and destination 50$: ; assemble buffer NEW MOVB (R1)+, R0 ; next char BEQ 70$ ; all done CMPB R0, #'' ; could it be 'Pn' ? BNE 55$ ; N CALL 300$ ; check it and substitute if necessary BCS 50$ ; already substituted 55$: MOVB R0, (R2)+ ; store BR 50$ ; next char from CMD Buf 70$: ; whole buffer moved to NEW TSTB CFETCH ; buffer already feched ? BLT 80$ ; Y- all done MOV #CDSC, R1 ; this descriptor to append CALL 200$ ; store 80$: ; all done, execute new command SUB #NEW, R2 ; calculate new length MOV R2, LEN ; and store TSTB OVMSG ; buffer overflow ? BEQ 85$ MOV #TOOLON, R0 ; Y- give Msg CALL IOMSG SEC 85$: RETURN ; CC-C only set if no command to execute 200$: ; append string with descriptor (R1) to NEW MOV (R1)+, R5 ; length BEQ 210$ ; empty MOV (R1), R1 ; source Addr 201$: CMP R2, #NEW+BUFSIZ ; in range ? BLO 202$ ; Y DECB OVMSG ; N- mark for Ovflw RETURN 202$: MOVB (R1)+, (R2)+ SOB R5, 201$ 210$: RETURN ; 300$: ; Substitute Pn's JSR R5, .SAVR1 ; save Regs CMPB (R1)+, #'P ; check next symbol BNE 301$ ; no match MOVB (R1)+, R3 ; get Parameter number SUB #'0, R3 ; decode BLE 301$ ; illegal CMP R3, #8. ; in range ? BHI 301$ ; N CMPB (R1)+, R0 ; endmark ? BEQ 302$ ; Y 301$: CLC ; tell no substit RTS PC 302$: ; substitution string found MOV R1, 2(SP) ; set up R1 after retunr ASL R3 ; Param num times 4 ASL R3 ADD #PDSC, R3 ; point to descriptor MOV R3, R1 CALL 200$ ; load it MOV R2, 2*2(SP) ; load R2 after return DECB CFETCH ; mark that parameter fetched SEC ; tell substituted RTS PC ; ; Convert to upper case, CC-C set if delimiter CNVUPC: ; check for delimiter CMPB R0, #'A+40 ; convert to upper case BLO 5$ CMPB R0, #'Z+40 BHI 5$ BICB #40, R0 ; convert to upper 5$: CMPB R0, #40 ; delimter ? SEC BEQ 20$ ; its a delimiter 10$: CLC ; character within string 20$: RTS PC ; ; Define new command in command buffer, or delete it ; NEWCMD: TSTB NOLOAD ; skip processing ? BNE 100$ ; Y CALL FNDCMD ; check if in table BCC 60$ ; Y- release old entry TST 2*4+PDSC ; P2 defined ? BNE 10$ ; Y- must load TST 3*4+PDSC+2 ; P3 with addr ? BEQ 100$ ; N- delete only 10$: ; insert new command MOV R2, R3 ; to entry after which to insert MOV LEN, R1 ; length of string BEQ 100$ ; ?? ADD #FTXT+1, R1 ; with overhead MOV #FREE, R0 CALL $RQCB ; request core block BCC 20$ ; ok MOV #NOPOOL, R0 ; No more Pool CALL IOMSG BR 100$ 20$: MOV (R3), (R0) ; link to previous entry BNE 21$ MOV R0, CMDB+2 ; we will be last one 21$: MOV R0, (R3) ; MOV R1, FLEN(R0) ; total length ADD #FTXT, R0 ; to start of text MOV #SAVB, R1 ; source MOV LEN, R2 ; length 24$: MOVB (R1)+, (R0)+ SOB R2, 24$ CLRB (R0) ; write delimiter 100$: SEC ; nothing to execute RETURN 60$: ; release old entry MOV (R0), (R2) ; link remainder BNE 62$ ; more entries MOV R2, CMDB+2 ; this was last one 62$: MOV FLEN(R0), R1 ; this length MOV R0, R2 MOV #FREE, R0 CALL $RLCB ; release it BR NEWCMD ; find more to release ; Recall Command from Fifo by key RECCMD: CLR -(SP) ; Save any Pointer to FIFO entry MOV FIFO, R4 ; Point to oldest Entry in Fifo BEQ 50$ ; empty MOV #NEW, R1 ; Source Buffer MOV #SAVB, R3 ; Destination Buffer SUB R1, R2 ; Length MOV R2, R5 ; Save it BGT 10$ ; non zero MOV FIFO+2, (SP) ; empty string - take previous entry BR 50$ ; from FIFO 10$: ; Store single char into SAVB MOVB (R1)+, R0 ; next char - convert to upper CALL CNVUPC ; check for delimiter MOVB R0, (R3)+ ; store char SOB R2, 10$ 20$: ; Check next entry in FIFO MOV #SAVB, R1 ; Source to Compare MOV R5, R2 ; Length of source MOV R4, R3 ; to entry ADD #FTXT, R3 ; to text of entry 25$: MOVB (R3)+, R0 ; next char BEQ 30$ ; EOL - no match CALL CNVUPC ; convert to uppercase CMPB R0, (R1)+ ; compare with source BNE 30$ ; no match SOB R2, 25$ ; match - try next char MOV R4, (SP) ; source exhausted - match found 30$: MOV (R4), R4 ; to next entry BEQ 50$ ; no more CMP R4, FIFPTR ; continue search ? BNE 20$ ; Y 50$: MOV (SP)+, FIFPTR ; Pop Pointer to entry if any CALL GEFIFO ; Load from FIFO (or delete NEW buffer) ; CLR FIFPTR ; initialize FIFO Ptr RETURN .END START