#TITLE  "FANLED - FANcy Line EDitor for TurboDOS 1.4x"
       #PAGE   132,66
       MODULE  "FanLEdit"
;
; THIS IS THE RELEASE VERSION OF FANLED
; v 1.10 as of 4-5-85
; v 1.11 as of 4-5-85 fixes ^Q problem
; v 1.30 as of 5-4-85 fixes ^Y problem, vers# in sync with 8 bit
;                     added ^U
; v 1.40 as of 7-13-85 now using COMSUB routines, fixed obscure bug
;
; ANOMALY:
;   The labels GN1, GN2, GN3 all point to GETNXT and are used
;   so save a few bytes.
;   FANLED is somewhat optimized, a more experienced programmer
;   may be able to squeeze a few more bytes out.  It shrunk over
;   250 bytes from the raw translation...
;
;       +-------------------------------+
;       | COMMAND CHARACTER DEFINITIONS |
;       +-------------------------------+
;
BEGLIN  ==      'A'-0X40                ; ^A - BEGINNING OF LINE
BACKCH  ==      'B'-0X40                ; ^B - CURSOR BACKWARDS
DELFOR  ==      'D'-0X40                ; ^D - DELETE CHAR FORWARD
ENDLIN  ==      'E'-0X40                ; ^E - END OF LINE
FORWCH  ==      'F'-0X40                ; ^F - CURSOR FORWARD
DELBAK  ==      'H'-0X40                ; ^H - DELETE CHAR BACKWARD
KILFOR  ==      'K'-0X40                ; ^K - KILL FORWARD
QUOTE   ==      'Q'-0X40                ; ^Q - QUOTE NEXT CHAR
RECALL  ==      'R'-0X40                ; ^R - RECALL PREVIOUS COMMAND LINE
ABORT   ==      'U'-0X40                ; ^U - ABORT LINE
KILBAK  ==      'X'-0X40                ; ^X - KILL BACKWARD
YANK    ==      'Y'-0X40                ; ^Y - YANK (UNKILL)
DELETE  ==      0X7F                    ; DEL- SAME AS ^H
;
; EXPERIMENTAL EQUATES
;
PUSHK   ==      'G'-0X40                ; PUSH KILL LINE
POPK    ==      'T'-0X40
;
;       +---------------+
;       | OTHER EQUATES |
;       +---------------+
;
CR      ==      0X0D            ; CARRIAGE RETURN
BELL    ==      7               ; BELL CHARACTER
LITC    ==      '^'             ; CARET (PREFIX FOR CONTROL CHAR DISPLAY)
;
;       +-------------------+
;       | DATA STORAGE AREA |
;       +-------------------+
;
       LOC     Data#
;
FORSPC::BYTE    'L'-0X40        ; NONDESTRUCTIVE FORWARD SPACE CHARACTER
QFLAG:  BYTE    0XFF            ; QUOTE NEXT FLAG
CLSAVE: WORD    0               ; COMMAND LINE STRUCTURE POINTER SAVE
CLEN:   BYTE    0               ; COMMAND LINE LENGTH
INSY:   BYTE    0               ; INSERT YANK FLAG
KILLEN: BYTE    0               ; LENGTH OF KILL BUFFER
KILBUF: RES     162             ; 162 BYTE KILL BUFFER
OLDLIN: RES     163             ; OLD COMMAND LINE
; EXPERIMENTAL STORAGE:
KILLEV: BYTE    0               ; KILL (STACK) LEVEL
KLEVAD: WORD    0               ; LEVEL POINTER ADDRESS
;
;       +---------------------------------------+
;       | COMMAND TABLE (PATCHABLE IN PAR FILE) |
;       +---------------------------------------+
;
;       Each command occupies 3 bytes, the command character
;       followed by the address of the command routine.
;
CMDTBL:
FANBG:: BYTE    BEGLIN
       WORD    CBEGLI
FANBK:: BYTE    BACKCH
       WORD    CBACKC
FANEL:: BYTE    ENDLIN
       WORD    CENDLI
FANFC:: BYTE    FORWCH
       WORD    CFORWC
FANDF:: BYTE    DELFOR
       WORD    CDELFO
FANDB:: BYTE    DELBAK
       WORD    CDELBA
FANKF:: BYTE    KILFOR
       WORD    CKILFO
FANQU:: BYTE    QUOTE
       WORD    CQUOTE
FANRC:: BYTE    RECALL
       WORD    CRECAL
FANKB:: BYTE    KILBAK
       WORD    CKILBA
FANYA:: BYTE    YANK
       WORD    CYANK
FANAB:: BYTE    ABORT
       WORD    CABORT
       BYTE    DELETE
       WORD    CDELBA
       BYTE    CR
       WORD    EXIT
; EXPERIMENTAL:
FANPU:: BYTE    PUSHK
       WORD    CPUSHK
FANPO:: BYTE    POPK
       WORD    CPOPK
NCMDS   ==      ($-CMDTBL)/3            ; NUMBER OF COMMANDS
;
;       +--------------+
;       | CODE SECTION |
;       +--------------+
;
       LOC     Code#
;
;       REGISTER USAGE:
;       ES:BX normally points to the current character in the command line
;          unless used otherwise
;       DX normally points to the kill buffer or the old line buffer
;       CH  always holds the current byte count for the main command line
;       CL  always holds the current cursor position in the command line
;       AL  usually holds a byte received from the keyboard and/or echoed

;       +--------------------+
;       | COMMON SUBROUTINES |
;       +--------------------+
;
;       GETCH - get character in AL, preserve all regs
;
GETCH:  PUSH    CX
       PUSH    DX
       PUSH    BX
       PUSH    ES
       CALL    CONIN#
       JMPS    POPR
;
;       ERROR - ring the bell
;
ERROR:  MOV     AL,=BELL
       JMPS    PUTCH
;
;       BKSPC - backspace
;
BKSPC:  MOV     AL,=8
;
;       PUTCH - display character in AL, preserve all regs
;
PUTCH:  PUSH    CX
       PUSH    DX
       PUSH    BX
       PUSH    ES
       MOV     CL,AL
       PUSH    AX
       CALL    CONOUT#
       POP     AX
POPR:   POP     ES
       POP     BX
       POP     DX
       POP     CX
       RET
;
;       DELLFT - delete left character with pointer movement
;          assume: ES:BX points into command line, CH holds
;          current byte count
;
DELLFT: DEC     CH              ; DECREMENT COUNT
       DEC     CL              ; DECREMENT CURSOR POINTER
       DEC     BX              ; DECREMENT POINTER
       ES
       CMP     [BX],=' '
       JNC     DELCHL          ; DELETE ONE CHAR IF NO CONTROL
       INC     DH              ; INCREMENT CONTROL CHAR COUNTER
       CALL    DELCHL
;
;       DELCHL - delete left character (bs,sp,bs)
;
DELCHL: PUSH    CX
       PUSH    DX
       PUSH    BX
       PUSH    ES
       CALL    DMS#
       BYTE    8,' ',8,0
       JMPS    POPR
;
;       GETCMD - AL=character, determine if it's an edit command
;          if edit command, DX=address, Z=reset
;
GETCMD: PUSH    BX
       PUSH    CX
       CMP     AL,=CR          ; IS IT A RETURN?
       JZ      ISCR            ; YUP!
       TEST    BYTE QFLAG,=0XFF ; SEE IF QUOTE FLAG SET
       MOV     BYTE QFLAG,=0XFF ; RESET QUOTE FLAG ANYWAY
       JZ      GETCMX          ; EXIT IF QUOTE FLAG
ISCR:   MOV     CH,=NCMDS
       MOV     BX,&CMDTBL      ; POINT TO COMMAND TABLE
GETCML: CMP     AL,[BX]
       JZ      GOTCMD          ; GOT A COMMAND
       INC     BX
       INC     BX
       INC     BX
       DEC     CH              ; KEEP SEARCHING
       JNZ     GETCML
       MOV     CH,AL
       XOR     AL,AL           ; SET ZERO FLAG
       MOV     AL,CH
       JMPS    GETCMX          ; EXIT
;
GOTCMD: INC     BX
       MOV     DX,[BX]
       OR      AL,AL           ; IF NOT ^@ TYPED
       JNZ     GETCMX          ;    THEN SKIP
       INC     AL              ; SPECIAL CASE WHERE ^@ IS NOT ATTENTION
       MOV     AL,=0
GETCMX: POP     CX
       POP     BX
       RET
;
;       Two external move routines are used, LDIR# and LDDR#.
;       Both are contained in COMSUB and work as follows:
;       Move CX bytes from AX:BX to BP:DX
;       ---------------------------------
;       LDIR moves from bottom to top, LDDR moves from top to bottom

;       +--------------------------+
;       | MAIN PROGRAM ENTRY POINT |
;       +--------------------------+



; INPUT:
;   ES:BX points to a data structure:
;   <BX>   = CLBLEN (command line buffer length
;   <BX+1> = actual command line length
;   <BX+2> = first byte of command line
; OUTPUT:
;   BX     = pointer to actual command line length
;   A      = actual command line length
;
INPLN:: XOR     CX,CX           ; ZERO COUNT AND CURSOR
       MOV     BYTE QFLAG,=0XFF ;CLEAR QUOTE FLAG
       ES
       MOV     AL,[BX]         ; GET MAX BYTE COUNT
       INC     BX              ; POINT TO CURRENT BYTE COUNT
       MOV     CLSAVE,BX       ; SAVE POINTER
       ES
       MOV     BYTE [BX],=0    ; BE SURE COMMAND LINE IS EMPTY
       INC     BX              ; POINT TO FIRST CHAR OF COMMAND LINE
       MOV     CLEN,AL         ; STORE MAX COMMAND LINE LENGTH
;
;       MAIN ROUTINE LOOP
;
GETNXT: CALL    GETCH           ; GET A CHARACTER
       CALL    GETCMD          ; CHECK IF COMMAND, RETURN ZERO IF NOT
       JZ      ASCII           ; NO COMMAND, ENTER IT INTO CMD LINE
       JMPI    DX              ; JUMP TO DE
;
;       enter AL into command line, echo character
;
ASCII:  CMP     CH,CLEN         ; END OF LINE REACHED?
       JNZ     NOLOV           ;   NOPE
       CALL    ERROR           ;      ELSE BEEP
       JMPS    GETNXT          ;         AND TRY AGAIN
;
NOLOV:  CMP     CH,CL           ; SEE IF AT END OF LINE
       JNZ     INSERT          ; INSIDE LINE, SO DO INSERT MODE
       ES
       MOV     [BX],AL
       INC     BX              ; INCREMENT
       INC     CH              ;    POINTERS
       INC     CL
       CALL    OUTCH
       JMPS    GETNXT          ; GO GET ANOTHER
;
;       INSERT - insert a character, move all others right
;
INSERT: CMP     CH,CLEN
       JNZ     __X
       CALL    ERROR           ; COMPLAIN
       JMPS    GETNXT          ;    AND EXIT IF TOO LONG
;
__X:    PUSH    CX              ; SAVE POINTERS
       SUB     CH,CL           ; SUBTRACT CURSOR POSITION
       MOV     CL,CH           ; SET COUNTER
       MOV     CH,=0           ; CX=NUMBER OF BYTES RIGHT OF CURSOR
       ADD     BX,CX           ; POINT TO END OF LINE
       MOV     DH,BH           ; DUPLICATE IN DX
       MOV     DL,BL
       INC     DX              ; DX POINTS PAST LINE
       INC     CX
       INC     CX
       PUSH    AX
       MOV     AX,ES
       MOV     BP,ES
       CALL    LDDR#           ; MOVE LINE UP ONE CHAR
       POP     AX
       INC     BX
       POP     CX              ; GET COUNTERS BACK
       INC     CH              ; INCREMENT CURSOR AND COUNT
       INC     CL
       INC     BX              ; INCREMENT POINTER
       ES
       MOV     [BX],AL         ; SAVE IT IN COMMAND LINE
       PUSH    BX              ; SAVE POINTER
       PUSH    CX              ; SAVE COUNTERS
       SUB     CH,CL           ; COUNT AGAIN
       INC     CH
       MOV     CL,CH
       ES
       CMP     [BX],=' '       ; COMPENSATE FOR INSERTED CTL CHAR
       JNC     INSL
       DEC     CL
INSL:   ES
       MOV     AL,[BX]
       CMP     AL,=' '
       JNC     __X
       INC     CL
__X:    CALL    OUTCH           ; DISPLAY THE CHAR
       INC     BX
       DEC     CH
       JNZ     INSL
;
INSD:   DEC     CL
INSDL:  CALL    BKSPC
       DEC     CL
       JNZ     INSDL
;
INSE:   POP     CX
       POP     BX
       INC     BX
       JMP     GETNXT
;
;       OUTCH - output a character, display control char if necessary
;
OUTCH:  CMP     AL,=' '         ; CHECK IF CTL CHARACTER
       JNC     NOCTL           ; SKIP IF NOT
       PUSH    AX              ; SAVE CHAR
       MOV     AL,=LITC        ; PREFIX CHAR
       CALL    PUTCH           ; DISPLAY IT
       POP     AX              ; GET CHAR BACK
       ADD     AL,=0X40        ; MAKE IT ALPHA
NOCTL:  JMP     PUTCH           ; DISPLAY CHAR
;
;       +----------------------------+
;       | COMMAND PROCESSOR ROUTINES |
;       +----------------------------+
;
;       CR typed -- exit back to turbodos
;
EXIT:   CMP     CH,CL           ; SEE IF WE'RE AT END OF LINE
       JZ      CNTXIT
       INC     BX              ; ELSE UP POINTERS
       INC     CL
       JMPS    EXIT
;
CNTXIT: PUSH    CX
       MOV     AL,=CR
       CALL    ECHO#           ; ECHO THE RETURN
       POP     CX
       MOV     BX,CLSAVE       ; GET COMMAND LINE POINTER
       ES
       MOV     [BX],CH         ; SAVE ACTUAL BYTE COUNT
       PUSH    BX              ; SAVE
       PUSH    CX              ;    REGISTERS
       MOV     CL,CH           ; SET UP COUNT
       MOV     CH,=0
       INC     CL
       MOV     DX,&OLDLIN
       MOV     AX,ES
       MOV     BP,DS
       CALL    LDIR#
       POP     CX              ; GET REGS BACK
       POP     BX
       MOV     AL,CH           ; BYTE COUNT IN A
       RET
;
;       CBEGLI - go to beginning of line
;
CBEGLI: INC     CL              ; SET UP CURSOR POINTER
CBEGL1: DEC     CL              ; DECREMENT CURSOR PTR
       JNZ     __X             ;    UNTIL ZERO
       JMPS    GN1
;
__X:    CALL    BKSPC
       DEC     BX
       ES
       CMP     [BX],=' '
       JNC     CBEGL1
       CALL    BKSPC
       JMPS    CBEGL1
;
;       CENDLI - go to end of line
;
CENDLI: CMP     CL,CH           ; IF CURSOR AT END OF LINE
       JNZ     __X             ;    THEN GET NEXT CHAR
       JMPS    GN1
;
__X:    INC     CL              ; POINT TO NEXT CHAR
       ES
       MOV     AL,[BX]
       INC     BX
       CMP     AL,=' '
       MOV     AL,FORSPC
       JNC     __Y
       CALL    PUTCH
__Y:    CALL    PUTCH
       JMP     CENDLI          ; AND SO ON
;
;       CBACKC - back 1 char
;
CBACKC: OR      CL,CL           ; IF AT LEFT
       JZ      GN1             ;    DO NOTHING
       CALL    BKSPC           ; ELSE BACKSPACE
       DEC     CL              ; DECREMENT COUNTER
       DEC     BX              ;    POINTER
       ES
       CMP     [BX],=' '
       JNC     GN1
       CALL    BKSPC
       JMPS    GN1
;
;       CFORWC - forward 1 char
;
CFORWC: CMP     CL,CH           ; IF AT END
       JZ      GN1             ;    DO NOTHING
       INC     CL              ; INCREMENT COUNTER
       ES
       CMP     [BX],=' '
       MOV     AL,FORSPC
       JNC     __X
       CALL    PUTCH
__X:    CALL    PUTCH           ; MOVE CURSOR
       INC     BX              ;    POINTER
GN1:    JMP     GETNXT
;
;       CQUOTE - do next char literally
;
CQUOTE: MOV     BYTE QFLAG,=0
       JMPS    GN1
;
;       CRECAL - recall previous command line
;
CRECAL: OR      CH,CH
       JZ      __X             ; COUNT MUST BE 0
       JMPS    GN1
;
__X:    CMP     OLDLIN,=BYTE 0  ; ANYTHING IN?
       JNZ     __Y             ;    NO, EMPTY
       JMPS    GN1
;
__Y:    PUSH    BX
       MOV     DX,&OLDLIN      ; GET OLD LINE
       XCHG    DX,BX           ; SET UP FOR MOVE
       DEC     DX
       MOV     CL,[BX]
       MOV     CH,=0
       PUSH    CX
       INC     CL
       MOV     AX,DS
       MOV     BP,ES
       CALL    LDIR#
       POP     CX
       MOV     CH,CL           ; GET COUNT INTO CH
       POP     BX              ; GET POINTER
DSLP:   ES
       MOV     AL,[BX]         ; GET BYTE
       CALL    OUTCH           ; DISPLAY IT WITH CTL CHAR EXPANSION
       INC     BX              ; POINT TO NEXT
       DEC     CH              ; UNTIL ALL DONE
       JNZ     DSLP
       MOV     CH,CL           ; COUNT = CURSOR
       JMPS    GN1             ; EXIT
;
;       CDELBA - delete previous character, move following chars to left
;
CDELBA: OR      CL,CL           ; SEE IF AT START OF LINE
       JZ      GN1
       MOV     DX,=0
       CALL    DELLFT          ; DELETE CHAR TO THE LEFT
       CMP     CL,CH
       JZ      GN2
       JMPS    MOVDEL          ; MOVE AFTER DELETE
;
;       CDELFO - delete following character, move remainder left
;
CDELFO: CMP     CH,CL           ; IF CURSOR AT RIGHT END
       JZ      GN2             ;    THEN DO NOTHING
       MOV     DX,=0
       DEC     CH
MOVDEL: MOV     AL,CH           ; SEE IF END OF LINE
       PUSH    CX              ; SAVE COUNTERS
       PUSH    BX              ; SAVE LINE PTR
       SUB     AL,CL           ; AL=NUMBER OF CHARS
       PUSH    AX
       INC     AL
       MOV     CL,AL
       MOV     CH,=0
       PUSH    DX              ; SAVE CONTROL CHAR COUNT
       MOV     DH,BH
       MOV     DL,BL
       INC     BX
       PUSH    AX
       MOV     AX,ES
       MOV     BP,AX
       CALL    LDIR#
       POP     AX
       POP     DX              ; GET CONTROL CHAR COUNT (0/1)
       POP     AX              ; GET BYTE COUNT
       POP     BX              ; GET LINE POINTER
       PUSH    BX              ; SAVE IT AGAIN
       MOV     CH,AL
       OR      AL,AL
       JNZ     MVDELL
       MOV     AL,=' '
       CALL    PUTCH
       CALL    PUTCH
       CALL    BKSPC
       CALL    BKSPC
       JMPS    MVDELQ
;
MVDELL: ES
       MOV     AL,[BX]
       CMP     AL,=' '
       JNC     MVD1
       INC     DL
MVD1:   CALL    OUTCH
       INC     DL              ; INCREMENT CHAR COUNT
       INC     BX
       DEC     CH
       JNZ     MVDELL
       MOV     AL,=' '
       CALL    PUTCH           ; WIPE OUT LAST CHAR
       CALL    PUTCH
       CALL    BKSPC
MVDEL1: MOV     CH,DL
       CALL    BKSPC
MVDEL2: CALL    BKSPC
       DEC     CH
       JNZ     MVDEL2
MVDELQ: POP     BX
       POP     CX
GN2:    JMP     GETNXT
;
;       CKILFO - kill all chars forward
;
CKILFO: CMP     CL,CH
       JZ      GN2             ; NOTHING TO KILL
       MOV     AL,CH
       SUB     AL,CL           ; GET BYTE COUNT
       MOV     CH,CL
       PUSH    CX              ; SAVE COUNT, CURSOR
       MOV     KILLEN,AL       ; STORE KILL BUFFER LENGTH
       MOV     CL,AL
       MOV     CH,=0
       PUSH    CX
       PUSH    BX              ; SAVE LINE POINTER
       MOV     DX,&KILBUF
       MOV     BP,DS
       MOV     AX,ES
       CALL    LDIR#           ; MOVE INTO KILL BUFFER (ES TO DS)
       POP     BX
       POP     CX
       PUSH    BX
       MOV     CH,CL
CKILF1: ES
       MOV     AL,[BX]
       INC     BX
       CMP     AL,=' '
       MOV     AL,=' '
       JNC     CKILF2
       CALL    PUTCH
       INC     CL
CKILF2: CALL    PUTCH
       DEC     CH
       JNZ     CKILF1
CKILF3: CALL    BKSPC
       DEC     CL
       JNZ     CKILF3
       POP     BX
       POP     CX
       JMPS    GN2
;
;       CKILBA - kill all chars backward
;
CKILBA: OR      CL,CL
       JZ      GN2             ; NOTHING TO KILL
       PUSH    CX              ; SAVE COUNTERS
       PUSH    BX              ; SAVE POINTER
       MOV     DX,CLSAVE       ; GET POINTER TO START
       INC     DX
       SUB     BX,DX           ; BX IS NOW LENGTH
       MOV     CH,BH
       MOV     CL,BL
       MOV     BX,&KILLEN      ; POINT TO KILL BUFFER
       MOV     [BX],CL
       INC     BX
       XCHG    DX,BX
       MOV     BP,DS
       MOV     AX,ES
       CALL    LDIR#           ; MOVE STUFF INTO KILL BUFFER (ES TO DS)
       POP     BX              ; GET OLD PTR
       POP     CX
       PUSH    CX
       PUSH    BX
CKILB1: DEC     BX
       ES
       CMP     [BX],=' '
       JNC     __X
       CALL    BKSPC
__X:    CALL    BKSPC
       DEC     CL
       JNZ     CKILB1
       MOV     DL,=0
CKILB2: ES
       MOV     AL,[BX]
       INC     BX
       CMP     AL,=' '
       MOV     AL,=' '
       JNC     CKILB3
       CALL    PUTCH
       INC     DL
CKILB3: CALL    PUTCH
       INC     DL
       DEC     CH
       JNZ     CKILB2
       MOV     CH,DL
CKILB4: CALL    BKSPC
       DEC     CH
       JNZ     CKILB4
       POP     BX              ; GET LINE PTR
       POP     CX              ; GET COUNTERS
       SUB     CH,CL           ; A NOW HAS BYTE COUNT
       MOV     CL,CH
       MOV     CH,=0
       PUSH    CX
       INC     CX
       MOV     DX,CLSAVE
       INC     DX
       PUSH    DX
       MOV     AX,DS
       MOV     BP,ES
       CALL    LDIR#           ; (DS TO ES)
       POP     BX
       POP     CX
       MOV     CH,CL
       MOV     CL,=0
       OR      CH,CH
       JZ      GN3
       PUSH    BX
       PUSH    CX
       MOV     DL,=0
CKILB5: ES
       MOV     AL,[BX]
       CMP     AL,=' '
       JNC     CKILB6
       INC     DL
       PUSH    AX
       MOV     AL,=LITC
       CALL    PUTCH
       POP     AX
       ADD     AL,=0X40
CKILB6: CALL    PUTCH
       INC     DL
       INC     BX
       DEC     CH
       JNZ     CKILB5
       MOV     CH,DL
CKILB7: CALL    BKSPC
       DEC     CH
       JNZ     CKILB7
       POP     CX
       POP     BX
GN3:    JMP     GETNXT
;
;       CYANK - yank kill buffer to current cursor
;
CYANK:  MOV     AL,KILLEN       ; GET KILL BUFFER LENGTH
       OR      AL,AL
       JZ      GN3             ; KILL BUFFER EMPTY
       ADD     AL,CH           ; CHECK TOTAL SIZE
       JC      __X             ; OVER 256 BYTES...
       CMP     CLEN,AL
       JNC     YNTL            ; GO AHEAD IF NOT TOO LONG
__X:    CALL    ERROR           ; BEEP IF TOO LONG
       JMPS    GN3
;
YNTL:   MOV     INSY,=0
       CMP     CH,CL           ; CHECK IF CURSOR AT END OF LINE
       MOV     AL,KILLEN       ; GET LENGTH OF KILL BUFFER
       JZ      NOMOVE          ; SKIP IF AT END OF LINE
       PUSH    CX              ; SAVE COUNT
       PUSH    BX              ; SAVE POINTER
       MOV     DL,AL
       MOV     DH,=0           ; DX = NUMBER OF BYTES TO BE FREED
       SUB     CH,CL
       MOV     CL,CH
       MOV     CH,=0           ; CX HAS BYTES TO BE MOVED
       ADD     BX,CX           ; POINT TO END OF LINE
       PUSH    BX
       ADD     BX,DX           ; POINT TO NEW END OF LINE
       XCHG    DX,BX
       POP     BX
       INC     CX
       MOV     AX,ES
       MOV     BP,AX
       CALL    LDDR#
       POP     BX
       POP     CX
       MOV     INSY,=0XFF
       MOV     AL,KILLEN       ; GET LENGTH DELETE CHAR FORWARD
NOMOVE: PUSH    CX
       PUSH    BX
       XCHG    BX,DX           ; DESTINATION TO DX
       MOV     BX,&KILBUF
       MOV     CL,AL
       MOV     CH,=0
       PUSH    CX
       MOV     AX,DS
       MOV     BP,ES
       CALL    LDIR#
       POP     DX
       POP     BX
       POP     CX
YDSLP:  ES
       MOV     AL,[BX]
       CALL    OUTCH
       INC     CH
       INC     CL
       INC     BX
       DEC     DL
       JNZ     YDSLP
       MOV     AL,INSY
       INC     AL
       JNZ     GN4
;
;       now redisplay remainder of line, then step back
;
       PUSH    BX              ; SAVE LINE PTR
       MOV     DL,=0           ; CHARACTER COUNT
       PUSH    CX
YTL1:   CMP     CH,CL
       JZ      YTL25
       ES
       MOV     AL,[BX]
       INC     CL
       CMP     AL,=' '
       JNC     YTL2
       INC     DL
YTL2:   INC     DL
       CALL    OUTCH
       INC     BX
       JMP     YTL1
;
YTL25:  POP     CX
YTL3:   CALL    BKSPC
       DEC     DL
       JNZ     YTL3
       POP     BX
GN4:    JMP     GN3
;
;       ABORT LINE
;
CABORT: MOV     CX,=0
       MOV     BX,CLSAVE
       INC     BX
       JMP     EXIT
;
;       EXPERIMENTAL STUFF
;
;       PUSH KILLED LINE
;
CPUSHK: CMP     KILLEV,=0               ; IF NOTHING STACKED
       JZ      __CPK                   ;   THEN CONTINUE
__CPUE: CALL    ERROR                   ;     ELSE BEEP
__GNXT: JMP     GETNXT                  ;     AND CONTINUE
;
__CPK:  PUSH    BX
       PUSH    CX
       MOV     BX,=170                 ; WE NEED 163 BYTES
       CALL    ALLOC#                  ; GET THEM
       TEST    AL,AL                   ; IF WE CAN
       JZ      __CP                    ;   OK, SO WE DON'T GET IT
       CALL    ERROR
__GX:   POP     CX
       POP     BX
       JMPS    __GNXT
;
__CP:   INC     KILLEV                  ; INCREMENT KILL KEVEL
       MOV     KLEVAD,BX               ; SAVE POINTER
       MOV     DX,BX
       MOV     BX,&KILLEN
       MOV     AX,DS
       MOV     BP,AX
       MOV     CX,=163                 ; 163 BYTES
       CALL    LDIR#
       JMPS    __GX
;
;       POP KILLED LINE
;
CPOPK:  CMP     KILLEV,=1               ; IF STACK ACTIVE
       JZ      __CPK                   ;   THEN CONTINUE
       CALL    ERROR                   ;     ELSE BEEP
__GNXT: JMP     GETNXT
;
__CPK:  PUSH    BX
       PUSH    CX
       MOV     KILLEV,=0               ; SET KILL LEVEL TO 0
       MOV     BX,KLEVAD               ; GET STACK POINTER
       MOV     DX,&KILLEN              ; GET DESTINATION ADDR
       MOV     AX,DS
       MOV     BP,AX
       MOV     CX,=163                 ; 163 BYTES
       CALL    LDI
R#                      ; MOVE IT
       MOV     BX,KLEVAD
       CALL    DEALOC#                 ; DEALLOCATE MEMORY
       POP     CX
       POP     BX
       JMPS    __GNXT                  ; QUIT
;
       END