; FANLED - FANcy Line EDitor for TurboDOS 1.4x ; ; RELEASE VERSION HISTORY ; 1.00 04/02/85 changed kill buffer logic to retain last kill buffer ; contents until ^K or ^X (rather than erasing at the ; beginning of each edit session). This now allows ; use of the kill buffer as "storage" for a frequently ; used command. ; 1.10 04/05/85 Optimized code for size ; 1.11 fixed quote problem ; 1.20 04/09/85 Made edit keys global ; 1.30 05/04/85 Fixed problem in ^Y routine ; name ('FANLED') ; ; Input: ; HL points to a data structure: ; = CLBLEN (command line buffer length ; = actual command line length ; = first byte of null-terminated command line ; Output: ; HL = pointer to actual command line length ; A = actual command line length ; .z80 ; ; Externals used: ; extrn dms,echo,conin,conout ; ; Global entry point: ; public inpln ; ; Global patch point: ; public forspc ; ; command character equates ; beglin equ 'A'-40h ; ^A - beginning of line backch equ 'B'-40h ; ^B - cursor backwards delfor equ 'D'-40h ; ^D - delete char forward endlin equ 'E'-40h ; ^E - end of line forwch equ 'F'-40h ; ^F - cursor forward delbak equ 'H'-40h ; ^H - delete char backward kilfor equ 'K'-40h ; ^K - kill forward quote equ 'Q'-40h ; ^Q - quote next char recall equ 'R'-40h ; ^R - recall previous command line abort equ 'U'-40h ; ^U - abort line kilbak equ 'X'-40h ; ^X - kill backward yank equ 'Y'-40h ; ^Y - yank (unkill) delete equ 7fh ; DEL- same as ^H ; ; other equates ; cr equ 0dh ; carriage return bell equ 7 ; bell character litc equ '^' ; caret (prefix for control char display) ; ; data storage areas ; dseg ; forspc: db 'L'-40h ; nondestructive forward space character qflag: db 0ffh ; quote next flag clsave: dw 0 ; command line structure pointer save clen: db 0 ; command line length insy: db 0 ; insert yank flag killen: db 0 ; length of kill buffer kilbuf: ds 162 ; 162 byte kill buffer oldlin: ds 162 ; old command line ; ; command table ; cmdtbl: fanbg:: db beglin dw cbegli fanbk:: db backch dw cbackc fanel:: db endlin dw cendli fanfc:: db forwch dw cforwc fandf:: db delfor dw cdelfo fandb:: db delbak dw cdelba fankf:: db kilfor dw ckilfo fanqu:: db quote dw cquote fanrc:: db recall dw crecal fankb:: db kilbak dw ckilba fanya:: db yank dw cyank fanab:: db abort dw cabort db delete dw cdelba db cr dw exit ncmds equ ($-cmdtbl)/3 ; number of commands ; cseg ; ; REGISTER USAGE: ; HL normally points to the current character in the command line ; unless used otherwise ; DE normally points to the kill buffer or the old line buffer ; B always holds the current byte count for the main command line ; C always holds the current cursor position in the command line ; A usually holds a byte received from the keyboard and/or echoed ; ; SUBROUTINES: ; ; GETCH - get character in A, preserve all regs ; getch: push bc push de push hl call conin jr popr ; ; BKSPC - backspace ; bkspc: ld a,delbak ; ; PUTCH - display character in A, preserve all regs ; putch: push bc push de push hl ld c,a push af call conout pop af popr: pop hl pop de pop bc ret ; ; ERROR - ring the bell ; error: ld a,bell jr putch ; ; DELLFT - delete left character with pointer movement ; assume: HL points into command line, B holds ; current byte count ; dellft: dec b ; decrement count dec c ; decrement cursor pointer dec hl ; decrement pointer ld a,(hl) ; get byte cp ' ' ; if control... jr nc,delchl ; delete one char if no control inc d ; increment control char counter call delchl ; ; DELCHL - delete left character (bs,sp,bs) ; delchl: push bc push de push hl call dms db 8,' ',88h jr popr ; ; GETCMD - A=character, determine if it's an edit command ; getcmd: push hl push bc cp cr jr z,iscr ld hl,qflag bit 0,(hl) set 0,(hl) jr z,getcmx iscr: ld b,ncmds ld hl,cmdtbl ; point to command table getcml: cp (hl) jr z,gotcmd ; got a command inc hl inc hl inc hl djnz getcml ; keep searching ld b,a xor a ; set zero flag ld a,b jr getcmx ; exit ; gotcmd: inc hl ld e,(hl) inc hl ld d,(hl) xor a inc a ; reset zero flag getcmx: pop bc pop hl ret ; ; ; MAIN PROGRAM ENTRY POINT ; ; inpln: xor a ; zero byte count/cursor buffer ld b,a ld c,a dec a ld (qflag),a ; reset quote flag ld a,(hl) ; get max byte count inc hl ; point to current byte count ld (clsave),hl ; save pointer ld (hl),0 ; be sure command line is empty inc hl ; point to first char of command line ld (clen),a ; store max command line length ; ; this is the main loop ; getnxt: call getch ; get a character call getcmd ; check if command, return zero if not jr z,ascii ; no command, enter it into cmd line push de ; jump to de ret ; ; enter A into command line, echo character ; ascii: push af ld a,(clen) ; get max line length cp b ; reached? jr nz,nolov ; nope pop af call error ; else beep jr getnxt ; and try again ; nolov: ld a,c ; see if at end of line cp b jr nz,insert ; inside line, so do insert mode pop af ld (hl),a inc hl ; increment inc b ; pointers inc c call outch jr getnxt ; go get another ; ; INSERT - insert a character, move all others right ; insert: ld a,(clen) ; get allowed length cp b jr nz,insne call error ; complain pop af jr getnxt ; and exit if too long ; insne: ld a,b ; get total chars in line sub c ; subtract cursor position push bc ; save pointers ld c,a ; set counter ld b,0 ; bc=number of bytes right of cursor add hl,bc ; point to end of line ld d,h ; duplicate in de ld e,l inc de ; de points past line inc bc inc bc lddr ; move line up one char inc hl pop bc ; get counters back inc b ; increment cursor and count inc c pop af ; now get character inc hl ; increment pointer ld (hl),a ; save it in command line push hl ; save pointer push bc ; save counters ld a,b sub c ; count again inc a ld b,a ld c,a ld a,(hl) ; compensate if ctl char inserted cp ' ' jr nc,insl dec c insl: ld a,(hl) cp ' ' jr nc,insnc inc c insnc: call outch ; disply the char inc hl djnz insl ; insd: ld b,c dec b insdl: call bkspc djnz insdl ; inse: pop bc pop hl inc hl jp getnxt ; ; OUTCH - output a character, display control char if necessary ; outch: cp ' ' ; check if ctl character jr nc,noctl ; skip if not push af ; save char ld a,litc ; prefix char call putch ; display it pop af ; get char back add a,40h ; make it alpha noctl: jp putch ; display char ; ; ; COMMAND PROCESSOR ROUTINES ; ; CR typed -- exit back to turbodos ; exit: ld a,c ; see if we're at end of line cp b ; if so continue jr z,cntxit inc hl ; else up pointers inc c jr exit ; cntxit: ld (hl),0 ; terminate command line push bc ld a,cr call echo ; echo the RETURN pop bc ld hl,(clsave) ; get command line pointer ld (hl),b ; save actual byte count push hl ; save push bc ; registers ld c,b ; set up count ld b,0 inc c ld de,oldlin ; point to previous line buffer ldir ; store current line there pop bc ; get regs back pop hl ld a,b ; byte count in A ret ; ; ; CBEGLI - go to beginning of line ; cbegli: inc c ; set up cursor pointer cbegl1: dec c ; decrement cursor ptr jr z,..gn1 ; until zero call bkspc dec hl ld a,(hl) cp ' ' call c,bkspc jr cbegl1 ; ; CENDLI - go to end of line ; cendli: ld a,c ; get cursor cp b ; if cursor at end of line jr z,..gn1 ; then get next char inc c ; point to next char ld a,(hl) inc hl cp ' ' ld a,(forspc) call c,putch call putch jr cendli ; and so on ; ; CBACKC - back 1 char ; cbackc: ld a,c ; get count or a ; if at left jr z,..gn1 ; do nothing call bkspc ; else backspace dec c ; decrement counter dec hl ; pointer ld a,(hl) cp ' ' call c,bkspc jr ..gn1 ; ; CFORWC - forward 1 char ; cforwc: ld a,c ; get count cp b ; if at end jr z,..gn1 ; do nothing inc c ; increment counter ld a,(hl) cp ' ' ld a,(forspc) call c,putch call putch ; move cursor inc hl ; pointer ..gn1: jp getnxt ; ; CQUOTE - do next char literally ; cquote: xor a ld (qflag),a jr ..gn1 ; ; CRECAL - recall previous command line ; crecal: inc b ; test if b=0 dec b jr nz,..gn1 ; count must be 0 ld a,(oldlin) ; anything in? or a jr z,..gn1 ; no, empty push hl ld de,oldlin ; get old line ex de,hl ; set up for move dec de ld c,(hl) ld b,0 push bc inc c ldir pop bc ld b,c ; get count into b pop hl ; get pointer dslp: ld a,(hl) ; get byte call outch ; display it with ctl char expansion inc hl ; point to next djnz dslp ; until all done ld b,c ; count = cursor jr ..gn1 ; exit ; ; CDELBA - delete previous character, move following chars to left ; cdelba: ld a,c ; see if at start of line or a jr z,..gn2 ld de,0 call dellft ; delete char to the left ld a,b cp c jr z,..gn2 jr movdel ; move after delete ; ; CDELFO - delete following character, move remainder left ; cdelfo: ld a,c ; if cursor at right end cp b jr z,..gn2 ; then do nothing ld de,0 dec b movdel: ld a,b ; see if end of line push bc ; save counters push hl ; save line ptr sub c ; a=number of chars push af inc a ld c,a ld b,0 push de ; save control char count ld d,h ld e,l inc hl ldir pop de ; get control char count (0/1) pop af ; get byte count pop hl ; get line pointer push hl ; save it again ld b,a or a jr nz,mvdell ld a,' ' call putch call putch call bkspc call bkspc jr mvdelq ; mvdell: ld a,(hl) cp ' ' jr nc,mvd1 inc e mvd1: call outch inc e ; increment char count inc hl djnz mvdell ld a,' ' call putch ; wipe out last char call putch call bkspc mvdel1: ld b,e call bkspc mvdel2: call bkspc djnz mvdel2 mvdelq: pop hl pop bc ..gn2: jp getnxt ; ; CKILFO - kill all chars forward ; ckilfo: ld a,b cp c jr z,..gn2 ; nothing to kill sub c ; get byte count ld b,c push bc ; save count, cursor ld (killen),a ; store kill buffer length ld c,a ld b,0 push bc push hl ; save line pointer ld de,kilbuf ldir ; move into kill buffer pop hl pop bc push hl ld b,c ckilf1: ld a,(hl) inc hl cp ' ' ld a,' ' jr nc,ckilf2 call putch inc c ckilf2: call putch djnz ckilf1 ld b,c ckilf3: call bkspc djnz ckilf3 pop hl pop bc ld (hl),0 jr ..gn2 ; ; CKILBA - kill all chars backward ; ckilba: ld a,c or a jr z,..gn2 ; nothing to kill push bc ; save counters push hl ; save pointer ld de,(clsave) ; get pointer to start inc de or a sbc hl,de ; hl is now length ld b,h ld c,l ld hl,killen ; point to kill buffer ld (hl),c inc hl ex de,hl ldir ; move stuff into kill buffer pop hl ; get old ptr pop bc push bc push hl ckilb1: dec hl ld a,(hl) cp ' ' ld a,8 call c,putch call putch dec c jr nz,ckilb1 ld e,0 ckilb2: ld a,(hl) inc hl cp ' ' ld a,' ' jr nc,ckilb3 call putch inc e ckilb3: call putch inc e djnz ckilb2 ld b,e ckilb4: call bkspc djnz ckilb4 pop hl ; get line ptr pop bc ; get counters ld a,b sub c ; a now has byte count ld c,a ld b,0 push bc inc bc ld de,(clsave) inc de push de ldir pop hl pop bc ld b,c ld c,0 ld a,b or a jr z,..gn3 push hl push bc ld e,0 ckilb5: ld a,(hl) cp ' ' jr nc,ckilb6 inc e push af ld a,litc call putch pop af add a,40h ckilb6: call putch inc e inc hl djnz ckilb5 ld b,e ckilb7: call bkspc djnz ckilb7 pop bc pop hl ..gn3: jp getnxt ; ; CYANK - yank kill buffer to current cursor ; cyank: ld a,(killen) ; get kill buffer length or a jr z,..gn3 ; kill buffer empty add a,b ; check total size jr c,er1 ; gee, much too much (>256)! ld e,a ld a,(clen) cp e jr nc,yntl ; go ahead if not too long er1: call error ; too long jr ..gn3 ; yntl: xor a ld (insy),a ld a,b cp c ; check if cursor at end of line ld a,(killen) ; get length of kill buffer jr z,nomove ; skip if at end of line push bc ; save count push hl ; save pointer ld e,a ld d,0 ; de = number of bytes to be freed ld a,b sub c ; a has bytes to be moved ld c,a ld b,0 ; bc has bytes tbm add hl,bc ; point to end of line push hl add hl,de ; point to new end of line ex de,hl pop hl inc bc inc bc lddr pop hl pop bc ld a,0ffh ld (insy),a ld a,(killen) ; get length of kill buffer nomove: push bc push hl ex de,hl ; destination to de ld hl,kilbuf ld c,a ld b,0 push bc ldir pop de pop hl pop bc ydslp: ld a,(hl) call outch inc b inc c inc hl dec e jr nz,ydslp ld a,(insy) inc a jr nz,..gn3 ; ; now redisplay remainder of line, then step back ; push hl ; save line ptr push bc ld e,0 ; character count ytl1: ld a,c cp b jr z,ytl25 inc c ld a,(hl) cp ' ' jr nc,ytl2 inc e ytl2: inc e call outch inc hl jr ytl1 ; ytl25: pop bc ytl3: call bkspc dec e jr nz,ytl3 pop hl jr ..gn3 ; ; abort line ; cabort: ld bc,0 ld hl,(clsave) inc hl jp exit ; END ointer ld e,a ld d,0 ; de = number of bytes to be freed ld a,b sub c ; a has byt