; MODULE: ZCPR3 Line Editor ; AUTHOR: Paul Pomerleau ; DATE: August 2, 1987 ; VERSION: 02 ;============================================================================= ; ; D E F I N I T I O N S S E C T I O N ; ;============================================================================= version equ 02 cr equ 0dh lf equ 0ah bell equ 07h tab equ 09h bdos equ 0005h bios equ 0000h ; Stuff from SYSLIB public cout,capin,cin,crlf,LED extrn KILL, KILSIZ, CMDLST, CMDLEN ; extrn cout,ccout,crlf ; TOO LONG!!!! Grr!!! extrn cst ;============================================================================= ; ; C O N F I G U R A T I O N A R E A ; ;============================================================================= VECTOR: dw SHIFTED ; Meta Key dw FCHR ; Right Char dw BCHR ; Left Char dw UP ; Up line dw DOWN ; Down line dw MBWORD ; Left word dw MFWORD ; Right word dw GOBOLN ; Start of line dw GOEOLN ; End of line dw FDEL ; Del char right dw DELCHR ; Del char left dw DELCHR ; Del char left dw FDWORD ; Del word right dw BDWORD ; Del word left dw CMDKILL ; Kill to semi-colon dw DELTOEND ; Delete to end of line dw DELLIN ; Delete line dw UNDO ; Reinsert deleted text dw TOGLIN ; Toggle insert dw ITAB ; Insert Tab char dw QINSERT ; Insert any char dw REPLOT ; Redraw line dw DONE ; End edit dw Warm ; Warm Boot LASTCASE: PUNC: db ',.:!#%^&<>[]{}()_+-=`~/\|; ',tab PUNCLEN equ $ - PUNC ;============================================================================= ; ; M A I N C O D E S E C T I O N ; ;============================================================================= LED: push de push hl ;-------------------------- EDIT: bit 0,a jr z,ED1 push af xor a ; On entry: DE = BUFFER, BC = LENGTH ld (de),a inc de ld (BUF_PTR),de ; Save the buffer position inc de ex de,hl add hl,bc ld (BUF_TOP_PTR),hl ; And the top of it pop af ED1: ld hl,INSFLG bit 1,a jr z,ED2 ld (hl),00h bit 2,a jr z,ED2 ld (hl),0ffh ED2: bit 3,a jr z,ED4 ld b,5 ED3: inc hl ld (hl),0 djnz ED3 ED4: bit 4,a call nz,OUTPUT2 ELOOP: xor a ld (NOOUT+1),a ; Turn printing on call GETKEY ld b,a ld a,(SHIFT) or b push af ; Mask in the highbit for META key xor a ld (SHIFT),a pop af cp ' ' jr c,CONTROL ; It's a command cp 127 jr nc,CONTROL call INSERT jr ELOOP CONTROL: call UCASE ld hl,ELOOP ; Return to... push hl ld hl,CMDLST ld bc,CMDLEN cpir ; Compare to CMDSTR jp nz,BEEP ; No match, check for insertion ld a,c ld a,CMDLEN - 1 sub c ; Get difference (how far in the command is) cp 18h jp nc,ADDON add a,a ; Double it (compensation for DWs) ld c,a ; Put that offset in BC ld hl,VECTOR add hl,bc ; Add it to CMDLST ld e,(hl) ; Get low byte inc hl ld d,(hl) ; Get high byte ex de,hl ; Put location in HL jp (hl) ; And go to that location SHIFTED: ld a,10000000b ; prepare for next command ld (SHIFT),a ret DELCHR: call DPOS ; Delete a char ret z call DELETE jp SHOWTOEND FCHR: call FWRAP ; Forward a char jp IPOS FWRAP: ld hl,(POS) ; Check for wrap ld a,(hl) or a ret nz pop hl jp GOBOLN BCHR: call BWRAP ; Backward a char jp DPOS BWRAP: ld hl,(POS) ; Check for wrap dec hl ld a,(hl) or a ret nz pop hl jp GOEOLN MBWORD: call BWRAP ; Go back a word BWORD: call DPOS ; Back a word without possible wrap ret z inc de call PUNCCP jr z,BWORD BWORD2: call DPOS ret z inc de call PUNCCP jr nz,BWORD2 dec de jp IPOS PUNCCP: ld hl,PUNC ; Check for punctuation ld bc,PUNCLEN cpir ret FDWORD: ld de,0 ; Delete forward a word call FWORD push de FDWBACK: ld a,d or e jr z,FDWENDBACK dec de call DPOS ; Back up to where we were jr FDWBACK FDWENDBACK pop de FDWDLOOP: ld a,e or d jp z,SHOWTOEND dec de push de call DELETE ; Delete same number of chars pop de jr FDWDLOOP BDWORD: ld de,0 ; Delete a word backwards call BWORD BDWRD1: ld a,d or e jp z,SHOWTOEND dec de push de call DELETE pop de jr BDWRD1 MFWORD: call FWRAP ; Go forward a word FWORD: call IPOS ; Forward a word without wrap ret z inc de call PUNCCP jr nz,FWORD FWORD2: call IPOS ret z inc de call PUNCCP jr z,FWORD2 dec de jp DPOS FDEL: call DELETE ; Delete forward a char ret z jp SHOWTOEND QINSERT: ; Quoted insert (get a key and put it in) call GETKEY or a ret z jr IJP ITAB: ld a,tab ; Insert a tab IJP: jp INSERT TOGLIN: ld hl,INSFLG ; Change insert (toggle) ld a,(hl) cpl ld (hl),a ret CMDKILL: ; Delete to a semi colon or end of line ld hl,(POS) ld de,KILL push de ld bc,kilsiz ; Stop before NULL in KILL ldir xor a ld (de),a pop hl CKL: push hl call DELETE pop hl inc hl cp ';' jr z,CKDONE or a jr nz,CKL CKDONE: ld (hl),0 jp SHOWTOEND DELLIN: ld hl,(BUF_PTR) ; Delete whole line ld de,KILL ld bc,kilsiz ; Stop at NULL in KILL ldir xor a ld (de),a DELLN1: call GOBOLN DELTOEND: call CLRTOEND ld hl,(POS) ld (hl),0 ret GOEOLN: call IPOS ; Go to end of line jr nz,GOEOLN ret GOBOLN: call DPOS ; Go to begining of line jr nz,GOBOLN ret REPLOT: ld hl,(POS) ; Redraw the line push hl call GOEOLN REPLT1: call crlf call OUTPUT pop de GOTOPOS: or a call IPOS sbc hl,de ret z jr c,GOTOPOS GP2: call DPOS ret z sbc hl,de ret z jr GP2 CAPIN: call cin ; Get a key and upcase it ; Fall through to UPCASE UCASE: push bc ; Upcase a char. Preserve high bit. push af and 80h ld b,a pop af and 7fh call UCASE2 or b pop bc ret UCASE2: ; Actual upcase function cp ' ' jr nc,NOTCTL add '@' NOTCTL: cp 'a' ret c cp 'z'+1 ret nc sub ' ' ret UP: ld hl,80 ; Go up a line BACKUP: ld a,h or l ret z dec hl push hl call DPOS pop hl ret z cp ' ' ; Control = two backups jr nc,BACKUP ld a,h or l ret z dec hl jr BACKUP DOWN: ld hl,80 ; Go down a line DOWNLOOP: ld a,h or l ret z dec hl push hl call IPOS pop hl ret z cp ' ' ; Control = 2 skips jr nc,DOWNLOOP ld a,h or l ret z dec hl jr DOWNLOOP DONE: pop hl ; Go back home... call GOEOLN ld a,13 call cout DOUT: push af ld hl,(BUF_PTR) ld bc,-1 COUNT_LOOP: ld a,(hl) inc hl inc bc or a jr nz,COUNT_LOOP ; 16 bit length in BC pop af ; Return Code in A pop hl pop de ret BEEP: ld a,bell ; Ring Bell (error) jp cout WARM: call GOEOLN ld a,13 call cout jp 0 ADDON: pop hl sub 23 jr DOUT ; --------------------------------------- ; Support routines for the commands above ; INSERT: ld e,a ; Put a char in the line ld a,(INSFLG) or a jr nz,YAINS ; Should we just overwrite? ld hl,(POS) ld a,(hl) or a ld a,e jr nz,OVERWRITE YAINS: xor a ld b,a push de call MOVEUP pop de jr z,BEEP ld a,e OVERWRITE: ld hl,(POS) ld (hl),a call IPOS jr SHOWTOEND DELETE: ld de,(POS) ; Delete current char ld a,(de) or a ret z push af ld hl,DELETED inc (hl) cp ' ' jr nc,NOINC2 inc (hl) NOINC2: call MOVEDOWN pop af or a ret OUTPUT: call crlf ; Put line on screen OUTPUT2: ld hl,(BUF_PTR) ld (POS),hl jr SHOWTOEND CLRTOEND: ; Draw spaces for each char ld hl,(POS) ; Control char = 2 spaces ld de,0 CLRLOOP: ld a,(hl) or a jr z,NOWBACK cp ' ' jr nc,CLR2 inc de call SPACE CLR2: call SPACE inc hl inc de jr CLRLOOP NOWBACK: ld a,d or e ret z dec de call BACK jr NOWBACK IPOS: ld hl,(POS) ; Forward a char by echoing it. ld a,(hl) or a ret z push af inc hl ld (POS),hl push bc ld b,a ld a,(NOOUT + 1) or a ld a,b pop bc call z,ccout pop af ret DPOS: ld hl,(POS) ; Back a char by ^H dec hl ; (2 for Control char) ld a,(hl) or a ret z push af ld (POS),hl cp ' ' call c,BACK call BACK pop af ret SHOWTOEND: ; Echo to the end of the line call PRINTHL ; and come back jr nz,SHOWLP ld hl,DELETED ld a,(hl) or a jr z,SHOWLP SHW1: push af call SPACE pop af dec a jr nz,SHW1 SHW2: call BACK dec (hl) jr nz,SHW2 SHOWLP: ld a,d or e ret z dec de call DPOS jr SHOWLP PRINTHL: ; Print the string at current position ld de,0 PHLOOP: call IPOS ret z inc de KILLFLG: ld a,0 or a ret nz push hl push de push bc ld c,11 call BDOS pop bc pop de pop hl or a jr z,PHLOOP call cin ld (GETKEY+1),a cp ' ' jr c,PHLOOP cp 127 ret nz jr PHLOOP GETKEY: ld b,0 ; Bring in a key xor a ; One keystroke buffer ld (GETKEY+1),a ld a,b or a call z,cin ret MOVEUP: ld hl,(POS) ; Move the line up to insert char ld a,' ' UPLOOP: ld b,(hl) ld (hl),a inc hl ld a,b or a jr nz,UPLOOP ld (hl),a ld de,(BUF_TOP_PTR) sbc hl,de jr z,MOVEDOWN or 1 ret MOVEDOWN: ; Move it down to delete one ld hl,(POS) ld d,h ld e,l DNLOOP: inc hl ld a,(hl) ld (de),a or a inc de jr nz,DNLOOP ret UNDO: ld hl,kill ; Insert the kill buffer xor a cpl ld (KILLFLG+1),a call UNDO1 xor a ld (KILLFLG+1),a jp SHOWTOEND UNDO1: ld a,(hl) inc hl or a ret z push hl call INSERT pop hl xor a jr UNDO1 ; ; Bdos console in. With no echo. ; CIN: push hl push de push bc ld hl,(1) ld de,9 add hl,de ld (hl),0C9h ; Turn off BIOS for echo push hl ld c,1 call BDOS pop hl ld (hl),0c3h ; Restore BIOS pop bc pop de pop hl ret CCOUT: push af ; Print control chars as ^c ; cp 8 ; For valid CCOUT, these are needed... ; jr z,OK ; But we don't make it public. ; cp 13 ; jr z,OK ; cp 10 ; jr z,OK cp ' ' jr nc,OK push af ld a,'^' call COUT pop af add '@' OK: call COUT pop af ret SPACE: ld a,' ' ; Print a space jr COUT BACK: ld a,8 ; Print a ^H COUT: push af ; Print a char push bc push de push hl ld e,a NOOUT: ld a,0 ; Check for silent running or a ld c,6 call z,pbdos pop hl pop de pop bc CPOP: pop af ret PBDOS: ld a,e ; Real print routine ld hl,SPOS cp 8 jr z,BACKP cp 13 jr z,ZEROP cp 7 jr z,NOIP cp 10 jr z,NOIP cp 9 jr z,TABCHR inc (hl) NOIP: jp BDOS ZEROP: ld (hl),1 BACKP: dec (hl) jr NOIP TABCHR: ld a,' ' call COUT ld a,7 and (hl) ret z jr TABCHR CRLF: ld a,cr ; Print a CR and a LF call cout ld a,lf jr cout ;============================================================================= ; B U F F E R S ;============================================================================= INSFLG: db 0ffh POS: dw 0 SHIFT: db 0 SPOS: db 0 DELETED: db 0 BUF_PTR: dw 0 BUF_TOP_PTR: dw 0 end