.title CLEEDI Command line editing module for CLE .ident /4.0.08/ ; See file CLE.MAC for edit history and comments .include /SY:[1,2]COMMON.MAC/ .include /IN:CLEMAC.MAC/ .enabl gbl .psect rwdata ,rw,d,lcl,rel,con .psect CLECTX ,rw,d,gbl,rel,con curpos: .word edipos curlen: .word edilen curcmd: .word edicmd maxsiz: .word edisiz clests: .word edists enckey: .word $enckey deckey: .word $deckey .psect $pdata ,ro,d,lcl,rel,con .psect $code ,i,ro,i,lcl,rel FALSE = 0 TRUE = 1 IN$MODE = 1 $DEBUG = 0 .iif ndf, $DEBUG, $DEBUG = 0 .MACRO ENCRYPT txt,key mov key ,-(sp) mov txt ,-(sp) call ENCRYPT .endm ENCRYPT .MACRO DECRYPT txt,key mov key ,-(sp) mov txt ,-(sp) call DECRYPT .endm DECRYPT .MACRO DEBUG txt,sts=1,docr=1 .if ne ,$DEBUG .if ne ,sts .save .psect $pdata $$ = . .if b , .ift .byte 15,12,0 .iff .asciz @txt@ .endc .even .restore mov #$$ ,-(sp) ; dump the text next please CALL mout ; to the terminal .globl mout ; perhaps .if nb , .ift .iif nb,docr, message .endc .endc .endc .endm DEBUG .enabl lsb kbredi::SAVE ; Save PRINT @r5 ; Prompt 10$: clr @curpos ; Assume at start of the line. clr @curlen ; No length mov 2(r5) ,r4 ; Buffer address clrb @r4 ; Insure starting with .ASCIZ 20$: CALL read1ch ; Read one character now mov r0 ,r3 ; Any data present? beq 90$ ; No, treat as a control Z asl r0 ; And dispatch jsr pc ,@scandsp(r0) ; Do it bcs 20$ ; Not done br 100$ ; Done ; 90$: mov #ER$EOF ,r0 ; Error, return END_OF_FILE clr r1 ; And no data 100$: UNSAVE ; Exit return .dsabl lsb .save .psect $pdata .even scandsp: .word BADDY ; 0 - NUL - ring bell .word TOGGLE ; 1 - ^A - Toggle insert/overstrike .word PREV ; 2 - ^B - Previous line .word CTRLC ; 3 - ^C - Control/C .word LEFT ; 4 - ^D - Move 1 char to left .word EOL ; 5 - ^E - End of line .word RIGHT ; 6 - ^F - Move 1 char to right .word BADDY ; 7 - ^G - ring bell .word SOL ; 10 - BS - Start of line .word NOOP ; 11 - TAB - Ignore .word LFSEEN ; 12 - LF - Delete prev word .word BADDY ; 13 - VT - ring bell .word BADDY ; 14 - FF - ring bell .word CRSEEN ; 15 - CR - Execute command .word BADDY ; 16 - ^N - ring bell .word BADDY ; 17 - ^O - ring bell .word BADDY ; 20 - ^P - ring bell .word BADDY ; 21 - ^Q - ring bell .word RETYPE ; 22 - ^R - Retype the line .word BADDY ; 23 - ^S - ring bell .word BADDY ; 24 - ^T - ring bell .word CTRLU ; 25 - ^U - Erase to SOL .word QUOTE ; 26 - ^V - Insert next character .word BADDY ; 27 - ^W - ring bell .word CTRLU ; 30 - ^X - Erase to SOL (same as ^U) .word BADDY ; 31 - ^Y - ring bell .word EOF ; 32 - ^Z - Zap line .word DOESC ; 33 - ESC - Handle escape sequence .word BADDY ; 34 - FS - ring bell .word BADDY ; 35 - GS - ring bell .word BADDY ; 36 - RS - ring bell .word BADDY ; 37 - US - ring bell .rept 177-40 .word INSCH ; 40-176 - Normal characters - insert .endr .word DORUB ; 177 - DEL - Rub out last character .rept 233-200 .word BADDY ; 200-232 - C1 Controls - ring bell .endr .word DO220 ; 233 - CSI - Do VT220 esc seq .rept 240-234 .word BADDY ; 234-237 - C1 Controls - ring bell .endr .rept 400-240 .word INSCH ; 240-177 - Normal characters - insert .endr esclst: .byte 'A&137 ,'B&137 ,'C&137 ,'D&137 ,0 .even escdsp: .word NOOP .word PREV ,NEXT ,RIGHT ,LEFT $wrdsep:.asciz % ,-.!"#$&'()+@[\]^{|}~/:;<>=?% $cc: .asciz /^C/ $cz: .asciz /^Z/ $cr: .asciz $crlf: .asciz $bakup: .asciz $beep: .asciz <7> $delet: .asciz / / $slash: .asciz /\/ $ceol: .asciz /[K/ $v5ceol:.asciz /K/ .even .restore Doesc: DEBUG ; ... cmp vttype ,#VT5X ; VT52? beq Do220 ; by pure coincidence, the same! CALL read1ch ; Get next in esc seq Do220: DEBUG ; You know CALL read1ch ; Ditto mov r0 ,r3 ; Get the data beq 90$ ; Error Exit SCAN r3 ,#esclst ; Process the character asl r0 ; Convert to word offset jsr pc ,@escdsp(r0) ; Do it br 100$ ; Ok 90$: sec ; Failure on the READ 100$: return ; And Exit Baddy: ; for now Quote: Noop: DEBUG ; ... sec ; Ignore return ; And Exit Insch: DEBUG ,FALSE ; ... sub #200 ,sp ; A temp buffer mov sp ,r2 ; A pointer to it tst r3 ; Null? beq 100$ ; Ignore cmp @curlen ,@maxsiz ; Too many chars? blo 10$ ; No PRINT #$beep ; Yes, signal error br 100$ ; Bye 10$: inc @curlen ; Save this mov @curpos ,r1 ; Get the offset into line add r4 ,r1 ; Where to stuff the data tstb @r1 ; Already at end of line? beq 20$ ; Yes, we have the stop to stuff it bit #IN$MODE,@clests ; Insert or overstrike? bne 15$ ; Insert movb r3 ,(r1)+ ; Overstrike br 30$ ; Exit 15$: STRCPY r2 ,r1 ; No, so save the data now movb r3 ,(r1)+ ; And insert the new character STRCPY r1 ,r2 ; And put the trailing data back in. br 30$ ; Now for the echoing 20$: movb r3 ,(r1)+ ; Already at eol, insert clrb @r1 ; And insure .ASCIZ 30$: dec r1 ; Back to to the new character inc @curpos ; Move over one bit #IN$MODE,@clests ; insert mode? beq 50$ ; nope, do simple echo PRINT r1 ; yes, show new text STRLEN r4 ; get length of input cmp @curpos ,r0 ; at EOL? beq 100$ ; if so, nothing to do mov @curpos ,r1 ; get current position sub r1 ,r0 ; compute difference 40$: PRINT #$bakup ; back up one sob r0 ,40$ ; simple br 100$ ; exit 50$: cmp inrub ,#0 ; part of rubout sequence? beq 60$ ; nope, don't bother PRINT #$slash ; yes, show the slash first mov #0 ,inrub ; and say we're done 60$: movb r3 ,ekbuf ; copy to echo buffer clr r1 ; ensure .ASCIZ movb r1 ,ekbuf+1 ; PRINT #ekbuf ; and echo 100$: add #200 ,sp ; Pop buffer sec ; Not done return ; Exit .sbttl More line editing routines ; SOL Move to start of line (Control H) Sol: DEBUG ; ... cmp vttype ,#TTY ; CRT? beq 110$ ; Nope, ignore tst @curpos ; Stop when at position 0 ble 100$ ; Done 10$: PRINT #$bakup ; Move dec @curpos ; Fix position bgt 10$ ; Next please 100$: clr @curpos ; Insure correct 110$: sec ; Not done return ; Exit ; EOL Move to End of Line, Control E Eol: DEBUG ; ... STRLEN r4 ; Find string length 10$: cmp @curpos ,r0 ; End yet? bhis 100$ ; Yes mov @curpos ,r1 ; Get current line position add r4 ,r1 ; Add in base of buffer movb @r1 ,ekbuf ; Copy it to private buffer clr r1 ; Ensure .ASCIZ movb r1 ,ekbuf+1 PRINT #ekbuf ; And echo it inc @curpos ; Fix this br 10$ ; Next 100$: sec ; Not done return ; Exit gotoeol:STRLEN r4 ; Find string length cmp @curpos ,r0 ; End yet? bhis 100$ ; Yes mov r0 ,@curpos ; set position to EOL 100$: return ; Exit ; Ctrlc and EOF Control C, Z on input .enabl lsb ; Temp Ctrlc: DEBUG ; ... PRINT #$cc ; Echo a control C mov #ER$EOF ,r0 clr r1 ; return null line return ; and exit Eof: DEBUG ; ... PRINT #$cz ; Echo a control Z br CRseen ; and process anyway (VMSism) .dsabl lsb ; Done .sbttl Carriage return (actually LF) processing ; CRseen. Saw a , expect a immediately. CRseen: DEBUG ; ... ; call READ1CH ; get the ; If is a private delimiter, it comes in without an ; Done. CR on input, store new line and bubble previous ones back Done: mov r5 ,-(sp) ; A scratch register we need DEBUG ; ... cmp inrub ,#0 ; In a harcopy rubout sequence? beq 5$ ; nope, skip PRINT #$slash ; yes, echo closing slash mov #0 ,inrub ; and say done 5$: PRINT #$crlf ; CR/LF STRLEN r4 ; Get byte count (we have CR or LF) mov r0 ,r1 ; Return it beq 90$ ; Nothing there, don't copy it. clr r2 ; The index mov lastcnt ,r3 ; Number of lines to do 10$: mov lastli(r2),r0 ; Look to find a free spot. tstb @r0 ; Empty? beq 60$ ; Yes add #2 ,r2 ; No, keep looking sob r3 ,10$ ; .... ; No room for command line. clr r2 ; The index mov r4 ,-(sp) ; Save it mov lastcnt ,r3 ; Number of lines to do dec r3 ; ... asl r3 ; See if this is same as last mov lastli(r3),r5 ; Current address inc r5 ; Skip the length mov r5 ,-(sp) ; Save DECRYPT r5,deckey ; Undo the old line STRLEN r4 ; Length cmpb -1(r5) ,r0 ; Same length bne 20$ ; No 15$: cmpb (r4)+ ,(r5)+ ; Check for string equality bne 20$ ; Not the same sob r0 ,15$ ; Same, check next 20$: mov (sp)+ ,r5 ; Restore old text pointer mov (sp)+ ,r4 ; Restore the current pointer ENCRYPT r5,enckey ; Restore the data asr r3 ; Restore r3 tst r0 ; Same ? bne 30$ ; No mov r3 ,@curcmd ; Yes, save index inc @curcmd ; next command will be this one + 1 br 100$ ; Exit 30$: 40$: mov lastli(r2),r0 ; Counted string format mov lastli+2(r2),r1 ; Again movb (r1) ,(r0)+ ; Copy the string length beq 55$ ; Can't happen, but may as well check clr r5 ; Counter for the copy operation bisb (r1)+ ,r5 ; Copy the byte count 50$: movb (r1)+ ,(r0)+ ; Copy the string now sob r5 ,50$ ; Next 55$: add #2 ,r2 ; Move up sob r3 ,40$ ; Next please ; 60$: mov lastli(r2),r1 ; Copy the line at last STRLEN r4 ; Get the line length mov @maxsiz ,r3 ; For padding with spaces movb r0 ,(r1)+ ; Copy the length beq 80$ ; Nothing mov r4 ,r5 ; Source string mov r1 ,-(sp) ; Save text address 70$: movb (r5)+ ,(r1)+ ; Copy the data now dec r3 ; Keep track of remaining space beq 75$ ; No room left sob r0 ,70$ ; Next please 74$: movb #40 ,(r1)+ ; Now space fill the line sob r3 ,74$ ; Next please 75$: mov (sp)+ ,r1 ; Restore text address ENCRYPT r1,enckey ; Encode it 80$: asr r2 ; Set 'Current' Command index mov r2 ,@curcmd ; And save it inc @curcmd ; next command will be this one + 1 br 100$ ; Exit 90$: movb #CR ,@r4 ; Return only a carriage return clrb 1(r4) ; .ASCIZ 100$: STRLEN r4 ; Get line length mov r0 ,r1 ; Where to return it. clr r0 ; No errors mov (sp)+ ,r5 ; Restore r5 ;clc ; All done return ; Exit ; PREV: Recall previous command line, UP-Arrow Key. Prev: DEBUG ; ... mov r5 ,-(sp) ; Save it 10$: dec @curcmd ; No, back up again blt 60$ ; went negative, no commands left mov @curcmd ,r2 ; Current command number asl r2 ; We want addresses today mov lastli(r2),r2 ; At last clr r3 ; Get length next bisb (r2)+ ,r3 ; Do it beq 10$ ; Nothing? mov @maxsiz ,r0 ; Copy all for DES types mov r4 ,r5 ; A copy of the destination 30$: movb (r2)+ ,(r5)+ ; Copy it sob r0 ,30$ ; Next please DECRYPT r4,deckey ; Decode the data add r4 ,r3 ; Point to the real end of data clrb @r3 ; Insure .asciz mov (sp)+ ,r5 ; Restore this cmp vttype ,#TTY ; CRT? bne 35$ ; Yes print #$crlf ; Nope, format for hardcopy br 50$ 35$: PRINT #$cr ; Start of line cmp vttype ,#VT5X ; VT52? beq 40$ ; yes PRINT #$ceol ; Clear br 50$ ; 40$: PRINT #$v5ceol ; Clear 50$: PRINT @r5 ; Prompt PRINT r4 ; Echo it STRLEN r4 ; Get length mov r0 ,@curlen ; And save it mov r0 ,@curpos ; set position to end of string br 100$ ; exit 60$: mov #-1,@curcmd ; before 1st command mov (sp)+ ,r5 ; Restore this clrb @r4 ; Nothing, kill the buffer clr @curlen ; clear length clr @curpos ; at start of command cmp vttype ,#TTY ; CRT? bne 65$ ; Yes PRINT #$crlf ; Nope, format for hardcopy br 80$ 65$: PRINT #$cr ; Start of line cmp vttype ,#VT5X ; VT52? beq 70$ ; yes PRINT #$ceol ; Clear br 80$ 70$: PRINT #$v5ceol ; Clear 80$: PRINT @r5 ; Prompt 100$: sec ; Not done yet return ; Exit Right: DEBUG ; ... cmp vttype ,#TTY ; CRT? beq 100$ ; Nope, skip it STRLEN r4 ; Get current length of the line cmp @curpos ,r0 ; Already at EOL? bhis 100$ ; Yes inc @curpos ; No, move over mov @curpos ,r1 ; Get current line position add r4 ,r1 ; Add in base of buffer dec r1 ; Actually, we want the previous one... movb @r1 ,ekbuf ; Copy it to private buffer clr r1 ; Ensure .ASCIZ movb r1 ,ekbuf+1 PRINT #ekbuf ; And echo it 100$: sec ; Not done return ; Exit .sbttl Rubouts and move left ; DORUB: Erase character Dorub: DEBUG ,FALSE ; ... tstb @r4 ; Is there ANYTHING in the line? beq 100$ ; No, it's a NO-OP tst @curpos ; Already at SOL (start of line)? bgt 10$ ; No clr @curpos ; Insure correct position br 100$ ; Off to common code 10$: cmp vttype ,#TTY ; CRT? beq 60$ ; Nope, we have a better way... PRINT #$bakup ; Go back one please dec @curpos ; Correct offset now dec @curlen ; Fix this up mov r4 ,r2 ; And move down add @curpos ,r2 ; Point to CURRENT character mov r2 ,r1 ; Again inc r1 ; Next position please STRCPY r2 ,r1 ; Copy data up a byte cmp @curpos,@curlen ; Are we at the end of the line? beq 50$ ; if so, go use optimized method cmp vttype ,#VT5X ; VT52? beq 20$ ; yes PRINT #$ceol ; Clear br 30$ ; 20$: PRINT #$v5ceol ; Clear 30$: PRINT r2 ; Dump buffer STRLEN r4 ; get length of input cmp @curpos ,r0 ; at EOL? beq 100$ ; if so, nothing to do mov @curpos ,r1 ; get current position sub r1 ,r0 ; compute difference 40$: PRINT #$bakup ; back up one sob r0 ,40$ ; simple br 100$ ; bail out 50$: PRINT #$delet ; just one, please... br 100$ ; and exit 60$: cmp inrub ,#0 ; Need to print initial slash? bne 70$ ; nope, already done PRINT #$slash ; yes, do it mov #1 ,inrub ; and say so 70$: dec @curpos ; Correct offset now dec @curlen ; Fix this up mov r4 ,r2 ; And move down add @curpos ,r2 ; Point to CURRENT character mov r2 ,r1 ; Again inc r1 ; Next position please SAVE movb -(r1) ,ekbuf ; deleted character to echo buffer clr r1 movb r1 ,ekbuf+1 ; .ASCIZ, please PRINT #ekbuf UNSAVE STRCPY r2 ,r1 ; Copy data up a byte 100$: sec ; Not done return ; Exit ; LFseen: Erase word LFseen: DEBUG ,FALSE ; ... cmp vttype ,#TTY ; CRT? beq 100$ ; Nope, ignore tstb @r4 ; Is there ANYTHING in the line? beq 100$ ; No, it's a NO-OP tst @curpos ; Already at SOL (start of line)? bgt 10$ ; No clr @curpos ; Insure correct position br 100$ ; Off to common code 10$: PRINT #$bakup ; Go back one please dec @curpos ; Correct offset now dec @curlen ; Fix this up mov r4 ,r2 ; And move down add @curpos ,r2 ; Point to CURRENT character mov r2 ,r1 ; Again inc r1 ; Next position please STRCPY r2 ,r1 ; Copy data up a byte tst @CURPOS ; at start of line? beq 40$ ; yes, so done SCAN -1(R2),#$wrdsep ; Is it a word terminator? tst R0 ; beq 10$ ; No, so delete another character 40$: cmp vttype ,#VT5X ; VT52? beq 50$ ; yes PRINT #$ceol ; Clear br 60$ ; 50$: PRINT #$v5ceol ; Clear 60$: PRINT r2 ; Dump buffer STRLEN r4 ; get length of input cmp @curpos ,r0 ; at EOL? beq 100$ ; if so, nothing to do mov @curpos ,r1 ; get current position sub r1 ,r0 ; compute difference 70$: PRINT #$bakup ; back up one sob r0 ,70$ ; simple br 100$ ; exit 100$: sec ; Not done return ; Exit ; Ctrlu: Erase to beginning of line Ctrlu: DEBUG ,FALSE ; ... cmp vttype ,#TTY ; CRT? beq 60$ ; Nope, skip this tstb @r4 ; Is there ANYTHING in the line? beq 100$ ; No, it's a NO-OP tst @curpos ; Already at SOL (start of line)? bgt 10$ ; No clr @curpos ; Insure correct position br 100$ ; Off to common code 10$: dec @curpos ; Correct offset now dec @curlen ; Fix this up mov r4 ,r2 ; And move down add @curpos ,r2 ; Point to CURRENT character mov r2 ,r1 ; Again inc r1 ; Next position please STRCPY r2 ,r1 ; Copy data up a byte tst @curpos ; at start of line? bne 10$ ; yes, so done PRINT #$cr ; back up PRINT @r5 ; re-draw prompt cmp vttype ,#VT5X ; VT52? beq 20$ ; yes PRINT #$ceol ; Clear br 30$ ; 20$: PRINT #$v5ceol ; Clear 30$: PRINT r2 ; Dump buffer STRLEN r4 ; get length of input cmp @curpos ,r0 ; at EOL? beq 100$ ; if so, nothing to do mov @curpos ,r1 ; get current position sub r1 ,r0 ; compute difference 40$: PRINT #$bakup ; back up one sob r0 ,40$ ; simple br 100$ 50$: cmp inrub ,#0 ; In a hardcopy rubout sequence? beq 60$ ; nope, skip PRINT #$slash ; yes, echo the slash mov #0 ,inrub ; say we are done 60$: PRINT #$crlf ; show cancel PRINT @r5 ; and prompt clr @curpos ; no position clr @curlen ; no length clrb @r4 ; and null-terminated 100$: sec ; Not done return ; Exit ; Left: Move left one character Left: DEBUG ; ... cmp vttype ,#TTY ; CRT? beq 100$ ; Nope, skip it tst @curpos ; Can we back up ? ble 100$ ; No dec @curpos ; Yes, backup a bit PRINT #$bakup ; And do so. 100$: sec ; Not done return ; Exit .sbttl Command recall and control R processing Next: DEBUG ; ... mov r5 ,-(sp) ; Save cmp vttype ,#TTY ; CRT? bne 4$ ; Yes PRINT #$crlf ; Nope br 6$ 4$: PRINT #$cr ; Start of line cmp vttype ,#VT5X ; VT52? beq 5$ ; yes PRINT #$ceol ; Clear br 6$ 5$: PRINT #$v5ceol ; Clear 6$: PRINT @r5 ; Prompt mov curcmd ,r2 ; Point to CURCMD mov lastcnt ,-(sp) ; Get the recall buffer count dec (sp) ; ... cmp @r2 ,(sp)+ ; Can we move up? bge 90$ ; No inc @r2 ; Yes, move up. mov @r2 ,r2 ; Copy it. asl r2 ; We want addresses today mov lastli(r2),r2 ; At last clr r3 ; Get length next bisb (r2)+ ,r3 ; Do it beq 90$ ; No command here? mov @maxsiz ,r0 ; Copy ALL for DES type routines mov r4 ,r5 ; A copy of the destination 30$: movb (r2)+ ,(r5)+ ; Copy it sob r0 ,30$ ; Next please DECRYPT r4,deckey ; Decode the data add r4 ,r3 ; Point to the real end of data clrb @r3 ; And force to .ASCIZ PRINT r4 ; Dump the data STRLEN r4 ; Get last line length mov r0 ,@curlen ; And save it mov r0 ,@curpos ; at end of command br 100$ ; Exit 90$: clrb @r4 ; Nothing, kill the buffer clr @curlen ; no command yet clr @curpos ; no position yet mov lastcnt ,@curcmd ; 100$: sec ; Not done yet mov (sp)+ ,r5 ; Restore return ; Exit Retype: DEBUG ; ... cmp vttype ,#TTY ; CRT? bne 4$ ; Yes cmp inrub ,#0 ; Nope, in a rubout sequence? beq 3$ ; No, skip slash echo PRINT #$slash ; yes, echo slash mov #0 ,inrub ; and say rubout sequence done 3$: PRINT #$crlf br 6$ 4$: PRINT #$cr ; Start of line cmp vttype ,#VT5X ; VT52? beq 5$ ; yes PRINT #$ceol ; Clear br 6$ 5$: PRINT #$v5ceol ; Clear 6$: PRINT @r5 ; Prompt PRINT r4 ; Dump the buffer STRLEN @r5 ; Get a new position now add @curpos ,r0 ; Get to correct position beq 100$ ; Nothing (?) STRLEN r4 ; get length of input cmp @curpos ,r0 ; at EOL? beq 100$ ; if so, nothing to do mov @curpos ,r1 ; get current position sub r1 ,r0 ; compute difference 10$: PRINT #$bakup ; back up one sob r0 ,10$ ; simple 100$: sec ; Not yet done return ; Exit Cantyp: call clrcns ; Eat up console data sec ; Not done return ; Exit Toggle: cmp vttype ,#TTY ; CRT? beq 100$ ; Nope, bail out mov #IN$MODE,r0 ; Toggle modes xor r0 ,@clests ; Do it 100$: sec ; Not done return ; Exit .end