;************************************************************************
;*                                                                      *
;*                      LINE EDIT ROUTINE                               *
;*                                                                      *
;************************************************************************
;(C) Copyright 1984 John Waycott - All Rights Reserved
;
;Permission is granted to freely copy this program provided that:
;
;       1. The copyright notices in this program must remain intact.
;       2. The program or modifications thereof are not sold for profit.
;
;If you have modifications, bug reports or enhancements please let me know.
;My address is:
;
;       John Waycott
;       6327 W Laredo St
;       Chandler, Az 85224
;       (702) 961-0193
;
;NOTE: The basic framework for this program was written several years ago
;when I was a rather inexperienced programmer and it probably shows in the
;code.  A lot of silly tricks were used to keep the code size to a minimum.
;Good luck to anyone attempting to modify it.
;
;EDITLI causes the system to enter an "edit" mode for all line-oriented
;keyboard input.  All of the VUE line-editing control characters are
;available.  Control-K as the very first character of a line causes the
;last line entered to appear.
;
;This program is invoked in the system initialization file with:
;
;       SYSTEM EDITLI.SYS/N
;
;Edit History:
;
;Revision         Date          Description
;--------       ---------       -----------
; 1.0(100)      16 Aug 84       Created
; 1.1(101)      10 May 85       Fixed inititalization so EDITLI works
;                               with other programs which fool with the
;                               monitor (e.g., TSASS, various CACHEs).
; 1.2(101)      20 May 85       Fixed problem with return from sys call
;                               skipping two bytes
;
; Flags in register D4:
;
B$INS = 0                       ; ^Q insert mode
B$SIL = 1                       ; Silent; set if KBD entered with echo
                               ; suppressed.
CH = 10
CI = 11
CK = 13
LF = 12
CL = 14
CR = 15
CQ = 21

VMAJOR = 1
VMINOR = 2
VSUB = 0
VEDIT = 101.
VWHO = 0

       SEARCH  SYS
       SEARCH  SYSSYM
       SEARCH  TRM
       OBJNAM  .SYS                    ; output name is EDITLI.SYS

       ASECT
       .=50
EM1010:                                 ; address of EM1010 trap vector
       PSECT

;
;EDITLI: must point to the first byte of this program.
;
EDITLI:
       PHDR    -1,0,PH$REE!PH$REU

       TYPECR  (C) Copyright 1984 John Waycott - All rights reserved

       MOV     EM1010,A0               ; Get 1010 Emulation vector
20$:    TST     (A0)+                   ; locate vector table
       BNE     20$
       ADD     #<4-2>*2,A0             ; get KBD routine address in A0
       CLR     D7                      ; use D7 to prevent sign extension
       MOVW    @A0,D7
       MOV     D7,A0
;
; find the sequence
;       CALL ....
;       TSTB    @A0
;
; by looking for the TSTB @A0 instruction.  The call is to TIN, which gets
; the next character from the terminal.
;
10$:    CMPW    (A0)+,#045020           ; is this the TSTB @A0 instruction?
       BNE     10$
;
; replace the sequence with a JMP.L KBD instruction.  We can do this
; because at this point, our routine can handle the keyboard input.
;
       LEA     A6,KBD
       MOV     A6,-(A0)                ; store <KBD> as jmp.l operand
       MOVW    #^H4EF9,-(A0)           ; store <jmp.l>
       EXIT

;
; This is the KBD routine.  Upon entry to this routine, A5 points to
; the terminal definition unit. A0 point to the JCB of the job.
; The keyboard routine has saved A0,A1,A3,A5,D1 on the stack.
;
; The system monitor handles the KBD call if:
;       1. the keyboard is in image or data mode
;       2. a command file is active, and the next line is not a :K
;       3. a terminal is attached.
;
KBD:    SAVE    A4,D0,D2,D3,D4,D5       ; save remaining registers
       MOV     T.ILB(A5),A3            ; set line buffer address
       MOV     A3,A4                   ; set addr of last byte in buffer
       ADD     T.ILS(A5),A4
       SUB     #4,A4                   ;   less CRLF and NULL terminators
       CLRB    @A4                     ; insure reasonable data
       PUSH    D1
       MOVB    #CQ,D1                  ; force ^Q to revive any ^S set.
       TRMICP
       POP     D1
       CLR     D4                      ; clear flags
       MOVW    #T$ECS,D7               ; set B$SIL if T$ECS is set.
       ANDW    @A5,D7
       BEQ     2$
       BSET    #B$SIL,D4
2$:     ORW     #T$IMI!T$ECS,@A5        ; set image mode, suppress echo
1$:     TSTB    T.STS(A5)               ; wait until all output flushed.
       BMI     1$

       MOVW    T.POO(A5),D3            ; set beginning position.
       MOVW    D3,D2                   ; set current position.
       MOV     A3,A2                   ; set buffer pointer
       TIN
       CMPB    D1,#CK
       BEQ     ISCK
       CLRB    @A2                     ; not control-K - clear buffer
       BR      NXT1
ISCK:   CALL    PAINT
NXT:    TIN                             ; get next character
NXT1:   TSTB    @A0                     ; check for interrupt
       JMI     C
       CMPB    D1,#127.                ; check for DEL
       JEQ     DEL
       CMPB    D1,#40                  ; printable?
       BLT     CCHAR                   ;   no
       BCALL   PRINT
       BR      NXT

;
; character is a control character
;
CCHAR:  ADD     D1,D1
       BEQ     NXT
       LEA     A6,10$[~D1]             ; table jump to appropriate routine
       ADDW    @A6,A6
       CALL    @A6
10$:    BR      NXT
       OFFSET  A
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  D
       OFFSET  RETURN
       OFFSET  F
       OFFSET  RETURN
       OFFSET  H
       OFFSET  F                       ; TAB always inserts.
       OFFSET  J
       OFFSET  RETURN
       OFFSET  L
       OFFSET  M
       OFFSET  N
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  Q
       OFFSET  R
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  U
       OFFSET  V
       OFFSET  W
       OFFSET  RETURN
       OFFSET  Y
       OFFSET  Z
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  RETURN
       OFFSET  RETURN

;
; printable character.  If printing over a TAB, insert the character.
;
PRINT:  CMPB    @A2,#CI
       BEQ     5$
       BTST    #B$INS,D4               ; check for insert mode
       BEQ     10$
5$:     PUSHW   D1
       CLRB    D1                      ; insure space insert.
       CALL    F
       RESTW   D1
       BNE     99$
10$:    CMP     A2,A4
       BEQ     99$
       CALL    OUTCH
       TSTB    @A2                     ; if at end of line, append a NULL
       BEQ     20$
       MOVB    D1,(A2)+
       RTN
20$:    MOVB    D1,(A2)+
       CLRB    @A2
       RTN
99$:    MOVB    #7,D1
       CALL    PUTC
RETURN: RTN

;
; DEL - delete character
;
DEL:    CMP     A2,A3                   ; if at BOL, do nothing
       BEQ     99$
       BTST    #B$INS,D4
       BEQ     20$
10$:    CALL    H
15$:    BCALL   D
       JMP     NXT
20$:    TSTB    @A2
       BEQ     10$
       CALL    H
       CMPB    @A2,#CI
       BEQ     15$
       MOVB    #40,@A2
       BTST    #B$SIL,D4               ; don't display if silent
       BNE     99$
       TTYI
       BYTE    ' ,CH,0,0
99$:    JMP     NXT


;
; delete word.
;
V:      CALL    NXTWRD
       CMP     A1,A2
       BEQ     D.X
       BR      DELBCH
;
; delete character at cursor.
;
D:      TSTB    @A2
       BEQ     D.X
       LEA     A1,1(A2)

DELBCH: PUSH    A2                      ; put current position on stack.
       CALL    LASTP
       POP     A6                      ; put current position in A6.
10$:    MOVB    (A1)+,(A6)+             ; move block of bytes down.
       BNE     10$
       CALL    REDRAW                  ; redraw the line.
D.X:    RTN

;
; clear line
;
Z:      BCALL   U
       BCALL   Y
       RTN
;
; Delete to end of line.
;
Y:      CALL    LASTP                   ; get last position.
       CLRB    @A2                     ; clear rest of line.
       CALL    REDRAW                  ; redraw the line.
       RTN

;
; go to beginning of line
;
U:      BCALL   H
       BNE     U
       RTN

;
; backspace
; z-bit is set if beginning of line.
;
H:      CMP     A2,A3                   ; check if at beginning
       BEQ     99$
       DEC     A2
       CALL    BCK
       LCC     #0
99$:    RTN

;
; move to end of line
;
N:      BCALL   L
       BNE     N
       RTN

;
; forward space
; z-bit set if end of line.
;
L:      TSTB    @A2
       BEQ     99$
       CALL    FWD
       INC     A2
       LCC     #0
99$:    RTN

;
; Repaint line
; Entry PAINT is called when an up-arrow is first entered.
; It repaints the line and removes the CRLF.
;
R:      BCALL   N
       TYPECR  ^R
       CLR     D3                      ; clear beginning position
       CLRW    D2                      ; clear current position
       MOV     A3,A2
PAINT:  MOVB    @A2,D1
       BEQ     99$
       CMPB    @A2,#CR
       BEQ     99$
       CMPB    @A2,#LF
       BEQ     99$
       CALL    OUTCH
       INC     A2
       BR      PAINT
99$:    CLRB    @A2
       RTN

;
; interrupt - clear buffer and return
;
C:      CLRB    @A3
       BR      DONE1
;
; end of line - carraige return or line feed.
;
; If we have a carraige return, look to see if a line feed is the next
; character waiting.  If so, discard it.  This prevents a type-ahead
; problem when entering multiple lines, but does not allow a LF
; to be entered ater a CR before the computer is accepting input.
M:      TST     T.ICC(A5)       ; any type-ahead?
       BEQ     10$             ;   no
       MOV     T.IBF(A5),A6    ;   yes - discard if LF
       CMPB    @A6,#LF
       BNE     10$
       TIN
10$:    TSTB    (A2)+
       BNE     10$
       MOVB    #CR,-1(A2)
       BR      DONE
J:      TSTB    (A2)+
       BNE     J
       DEC     A2
DONE:   MOVB    #LF,(A2)+       ; store final LF and NULL
       CLRB    @A2
       TST     (SP)+           ; pop stack and echo CRLF
       CRLF
       MOVB    #LF,JOBCMS+1(A0); store LF in upper byte of JOBCMS word
10$:
;
;If input is in upper case, convert the string to upper case
;
       MOVW    @A5,D7
       ANDW    #T$ILC,D7
       BNE     DONE1
       MOV     A3,A2
20$:    MOVB    @A2,D1
       BEQ     DONE1
       UCS
       MOVB    D1,(A2)+
       BR      20$

DONE1:  ANDW    #~<T$IMI>,@A5           ; restore image mode
       BTST    #B$SIL,D4               ; restore echo if B$SIL is clear
       BNE     10$
       ANDW    #~<T$ECS>,@A5
10$:    MOV     A3,A2                   ; set return pointer
       ANDW    #~<C.KIN!C.PTL>,JOBCMS(A0) ; clear :K or :P in cmd file
       REST    A4,D0,D2,D3,D4,D5
       REST    A0,A1,A3,A5,D1          ; restore registers from sys call
       RTE                             ; return from system call

;
; Toggle insert mode
;
Q:      BCHG    #B$INS,D4
       MOVB    #7,D1
       CALL    PUTC
       RTN

;
; insert a space or tab in the line.
; If D1 is CI * 2, insert tab.
; If no room in buffer, z-bit is cleared.
;
F:      MOV     A2,A1                   ; find end of line
10$:    TSTB    (A1)+
       BNE     10$
       CMP     A1,A4
       BLO     20$
       LCC     #0                      ; clear z-bit - no room for insert
       RTN
20$:    MOVB    -(A1),1(A1)
       CMP     A2,A1
       BNE     20$
       MOVB    #40,@A2                 ; insert space or tab
       CMPB    D1,#CI_1
       BNE     30$
       MOVB    #CI,D1                  ; if tab insert, move past the tab.
       MOVB    D1,(A2)+
       CALL    OUTCH                   ; output the tab
30$:    CALL    LASTP                   ; repaint the line
       CALL    REDRAW
       LCC     #4                      ; return success.
       RTN

;
; Move cursor to beginning of word
;
A:      CALL    H                       ; backspace
       BEQ     99$                     ; at beginning of line
       ALF
       BEQ     20$
       NUM
       BNE     A
20$:    CALL    H
       BEQ     99$
       ALF
       BEQ     20$
       NUM
       BEQ     20$
       CALL    L
99$:    RTN

;
; move to next word
;
W:      BCALL   NXTWRD
10$:    CMP     A2,A1
       BHIS    99$
       CALL    L
       BR      10$
99$:    RTN


;
; nxtwrd - point a1 to the next word in the line.
;
NXTWRD: MOV     A2,A1                   ; save a2
10$:    TSTB    @A2
       BEQ     99$
       INC     A2
       ALF                             ; skip alphanumerics
       BEQ     10$
       NUM
       BEQ     10$
20$:    TSTB    @A2
       BEQ     99$
       CMP     A2,A4
       BEQ     99$
       INC     A2
       ALF
       BEQ     99$
       NUM
       BNE     20$
99$:    XCH     A1,A2                   ; restore a2 and set a1.
       RTN

;backspace the display.  If backspace is over a character, simply output
;a control-H to do the backspace.  If backspacing over a tab, calculate
; how many backspaces to actually do.
;
BCK:    CMPB    @A2,#CI                 ; if not tab, backspace.
       BEQ     10$
       MOVB    #CH,D1
       CALL    PUTC
       DECW    D2                      ; decrement position
       RTN
10$:    MOVW    D3,D0                   ; get beginning position count.
       MOV     A3,A6                   ; beginning of buffer
CHKTB:  CMP     A6,A2                   ; reached current character?
       BHIS    CHKTBX                  ;   yes
       CMPB    (A6)+,#CI               ; increment pos by tabstop if a tab.
       BEQ     10$
       INC     D0
       BR      CHKTB
10$:    ADD     #10,D0
       ANDW    #~7,D0
       BR      CHKTB
CHKTBX: SUBW    D2,D0
       NEGW    D0
       MOVB    #CH,D1                  ; output backspaces.
10$:    CALL    PUTC
       DECW    D2
       DECW    D0
       BGT     10$
99$:    RTN

;
; move cursor forward.
; If forward over tab, compute new position and output necessary spaces.
;
FWD:    MOVW    #1,D0                   ; default count
       CMPB    @A2,#CI
       BNE     OUTCL
10$:    MOVW    D2,D0                   ; get output position
       ANDW    #7,D0                   ; compute no. of spaces to output
       ADDW    #-10,D0
       NEGW    D0
OUTCL:  MOVB    #CL,D1
10$:    BCALL   PUTC
       INCW    D2
       DECW    D0
       BGT     10$
       RTN

;
;outch - output a character.  Adjust output position stored in D2.
;If outputting a TAB, output spaces to tab position.
;posch - does same but dows not write char to terminal.  Returns number
;of spaces moved in D7.
;
OUTCH:  BCALL   POSCH                   ; set position
       CMPB    D1,#CI                  ; if tab, output spaces, else
       BEQ     10$
       BCALL   PUTC
       RTN
10$:    MOVB    #40,D1
       PUSHW   D7
       BCALL   PUTC
       POPW    D7
       DECW    D7
       BGT     10$
       RTN

POSCH:  MOVW    #1,D7
       CMPB    D1,#CI
       BNE     99$
       MOVW    D2,D7
       ANDW    #7,D7
       ADDW    #-10,D7
       NEGW    D7
99$:    ADDW    D7,D2
       RTN

;
; putc - output character in D1 to terminal if echo is not suppressed.
;
PUTC:   BTST    #B$SIL,D4
       BNE     99$
       TTY
99$:    RTN

;
;lastp - returns the screen position of the last character on the line in d0.
;
LASTP:  MOV     A2,A6
       MOVW    D2,D0                   ; save current position
10$:    MOVB    (A6)+,D1
       BEQ     99$
       CALL    POSCH                   ; add to position
       BR      10$
99$:    XCH     D2,D0                   ; restore d2, d0 = last position.
       RTN

;
; redraw - redraw rest of line and clear end garbage.
; Called after a character or word delete.
; Upon entry, D2 contains current position, D0 contains the last position of
; the line before it was modified.
; The rest of the line is redrawn, and spaces are drawn to erase any garbage
; at the end.  Finally, the cursor is backed up to the original position.
;
REDRAW: SAVE    A2,D2
       CALL    PAINT                   ; paint the new line
10$:    CMPW    D2,D0                   ; at final position?
       BHIS    GOBACK                  ;   yes, go back again.
       MOVB    #40,D1                  ;   no, output a space.
       CALL    OUTCH
       BR      10$
GOBACK: REST    A2,D2                   ; restore original positions.
10$:    CMPW    D0,D2                   ; back to original?
       BLOS    99$                     ;   yes, all done.
       MOVB    #CH,D1                  ;   no, backspace.
       BCALL   PUTC
       DECW    D0
       BR      10$
99$:    RTN

       END