;
; SYSLIB Module Name:  SINLIN
; Author:  Richard Conn
; SYSLIB Version Number:  2.0
; Module Version Number:  1.0
; Module Entry Points:
;       INLINE
; Module External References:
;       CCOUT           CIN             COUT            CRLF
;

;
;  INLINE --
;       INPUT LINE EDITOR
;       INPUT A LINE FROM CON: INTO THE BUFFER POINTED TO BY H&L
;       INPUT PARAMETERS:
;               HL PTS TO BUFFER
;               A = ECHO FLAG (A=0 MEANS NO ECHO)
;       OUTPUT PARAMETERS:
;               NO REGS AFFECTED
;       INPUT LINE EDITING CHARACTERS ARE --
;               <BS> -- DELETE PREVIOUS CHAR AND BACK UP CURSOR (SOFTCOPY)
;               <DEL> -- DELETE PREVIOUS CHAR AND ECHO IT (HARDCOPY)
;               <CR> -- INPUT COMPLETE
;               <LF> -- SKIP DOWN TO NEXT LINE AND INSERT <CR> <LF>
;               CTRL-X -- ERASE CURRENT LINE AND BACK UP CURSOR (SOFTCOPY)
;               CTRL-U -- ERASE CURRENT LINE (HARDCOPY)
;               CTRL-R -- RETYPE CURRENT LINE
;               CTRL-E -- GO TO NEXT LINE
;
       EXT     CCOUT
       EXT     CIN
       EXT     COUT
       EXT     CRLF

PUTRG   MACRO
       PUSH    B       ; SAVE BC, DE, HL
       PUSH    D
       PUSH    H
       ENDM
GETRG   MACRO
       POP     H       ; RESTORE HL, DE, BC
       POP     D
       POP     B
       ENDM


;
;  MAIN INLINE ENTRY POINT
;
INLINE::
       PUTRG           ; SAVE REGISTERS
       PUSH    PSW     ; SAVE PSW
       STA     ECHO    ; SAVE ECHO FLAG
       SHLD    START   ; SAVE START OF STRING

;  INLINE RESTART LOOP
INL0:
       LHLD    START   ; GET START OF STRING
       MVI     C,0     ; SET CHAR COUNT

;  MAIN LOOP
INL1:
       CALL    CIN     ; GET INPUT CHAR
       CPI     NULL    ; DO NOT PERMIT <NULL>
       JZ      INL1
       CPI     BS      ; BACKSPACE?
       JZ      INBS
       CPI     DEL     ; DELETE?
       JZ      INDEL
       CPI     TAB     ; TABULATE?
       JZ      INTAB
       CPI     CR      ; CARRIAGE RETURN?
       JZ      INCR
       CPI     LF      ; LINE FEED?
       JZ      INLF
       CPI     CTRLU   ; CTRL-U?
       JZ      RESTRT
       CPI     CTRLX   ; CTRL-X?
       JZ      REXSTRT
       CPI     CTRLR   ; CTRL-R?
       JZ      RETYPE
       CPI     CTRLE   ; CTRL-E?
       JZ      NEWLINE
       MOV     M,A     ; STORE CHAR
       INX     H       ; PT TO NEXT
       CALL    CTRL    ; PRINT CHAR
       INR     C       ; INCR CHAR CNT
       JMP     INL1




;
;  ** INLINE MODULES **

;  NEWLINE -- ECHO <CR> <LF> AND CONTINUE
NEWLINE:
       CALL    CRLF
       JMP     INL1

;  TAB -- TABULATE TO NEXT TAB STOP
INTAB:
       MOV     M,A     ; STORE <TAB>
       INX     H       ; PT TO NEXT CHAR POSITION
       CALL    INTAB0  ; TABULATE
       JMP     INL1

;  CTRL-R -- RETYPE CURRENT LINE
RETYPE:
       MVI     M,0     ; STORE END OF STRING CHAR
       MVI     C,0     ; RESET CHAR CNT
       LHLD    START   ; GET START ADDRESS
       CALL    HASH    ; PRINT HASH CHAR
RETY1:
       MOV     A,M     ; GET CHAR
       ORA     A       ; ZERO?
       JZ      INL1    ; CONTINUE
       CALL    CTRL    ; PRINT IT
       MOV     A,M     ; GET CHAR AGAIN
       CPI     TAB     ; DON'T COUNT IF <TAB>
       JZ      RETY2
       CPI     BEL     ; DON'T COUNT IF <BEL>
       JZ      RETY2
       INR     C       ; INCR CHAR CNT
RETY2:
       INX     H       ; PT TO NEXT CHAR
       JMP     RETY1

;  CTRL-U -- ERASE LINE AND RESTART
RESTRT:
       CALL    HASH    ; PRINT HASH CHAR
       JMP     INL0    ; START UP AGAIN

;  CTRL-X -- ERASE (AND BACKSPACE) LINE AND RESTART
REXSTRT:
       MOV     A,C     ; CHECK FOR EMPTY LINE
       ORA     A       ; 0 CHARS?
       JZ      INL0
       CALL    EXBS    ; <BS>
       JMP     REXSTRT

;  LINE FEED -- INSERT <CR> <LF> AND ECHO <CR> <LF>
INLF:
       MVI     M,CR    ; STORE <CR>
       INX     H       ; PT TO NEXT
       MVI     M,LF    ; STORE <LF>
       INX     H       ; PT TO NEXT
       MVI     C,0     ; RESET CHAR CNT
       LDA     ECHO    ; ECHO ON?
       ORA     A       ; 0=NO
       CNZ     CRLF    ; NEW LINE
       JMP     INL1

;  DELETE -- DELETE PREVIOUS CHAR AND ECHO DELETED CHAR
INDEL:
       CALL    BOL     ; BEGINNING OF LINE?
       JZ      INL1    ; CONTINUE
       DCX     H       ; BACK UP
       MOV     A,M     ; GET CHAR
       CALL    CTRL    ; PRINT CHAR
       CPI     BEL     ; DON'T CHANGE COUNT IF <BEL>
       JZ      INL1
       INR     C       ; INCR DISPLAY CHAR COUNT
       JMP     INL1

;  BACKSPACE -- DELETE PREVIOUS CHAR AND BACK UP CURSOR
INBS:
       CALL    EXBS    ; EXECUTE <BS>
       JMP     INL1

;  BACKSPACE ROUTINE
EXBS:
       CALL    BOL     ; BEGINNING OF LINE?
       RZ              ; CONTINUE IF SO
       DCR     C       ; DECR COUNT
       DCX     H       ; BACK UP
       LDA     ECHO    ; ECHO ON?
       ORA     A       ; 0=NO
       RZ
       MVI     A,BS    ; PRINT <BS>
       CALL    COUT
       MVI     A,' '   ; <SP>
       CALL    COUT
       MVI     A,BS    ; <BS>
       CALL    COUT
       RET

;  CARRIAGE RETURN -- DONE; STORE ENDING ZERO
INCR:
       MVI     M,0     ; STORE ENDING ZERO
       LDA     ECHO    ; ECHO ON?
       ORA     A       ; 0=NO
       CNZ     CRLF    ; NEW LINE
       POP     PSW     ; RESTORE PSW
       GETRG           ; RESTORE REGS
       RET




;
;  ** SUPPORT ROUTINES **
;  BOL -- RETURNS W/ZERO FLAG SET IF USER AT BEGINNING OF LINE
BOL:
       XCHG            ; DE=HL
       LHLD    START   ; GET START ADR
       XCHG            ; HL RESTORED
       MOV     A,D     ; CHECK FOR MATCH
       CMP     H       ; MATCH?
       RNZ             ; NO MATCH
       MOV     A,E     ; CHECK FOR COMPLETE MATCH
       CMP     L
       RNZ             ; NO MATCH
       PUSH    PSW     ; SAVE FLAGS
       MVI     A,BEL   ; BEEP
       CALL    COUT
       POP     PSW
       RET

;  CTRL -- IF CHAR>=<SP>, PRINT IT; OTHERWISE, PRINT AS CTRL-CHAR
CTRL:
       PUSH    B       ; SAVE BC
       MOV     B,A     ; SAVE CHAR IN B
       LDA     ECHO    ; CHECK ECHO FLAG
       ORA     A       ; 0=NO ECHO
       MOV     A,B     ; RESTORE CHAR
       POP     B       ; RESTORE BC
       RZ              ; NO OUTPUT IF NO ECHO
       CPI     ' '     ; <SP>?
       JC      CTRL1
       JMP     COUT    ; PRINT IT NORMALLY
CTRL1:
       CPI     TAB     ; TRAP <TAB>
       JZ      INTAB0
       JMP     CCOUT   ; PRINT WITH CTRL-CHAR PROCESSING

;  HASH -- PRINT HASH MARK FOLLOWED BY <CR> <LF>
HASH:
       MVI     A,'#'   ; PRINT HASH CHAR
       CALL    COUT
       JMP     CRLF

;  BUFFERS
START:
       DS      2       ; TEMPORARY STORAGE FOR BUFFER START ADDRESS
ECHO:
       DS      1       ; ECHO FLAG (0=NO ECHO)

;  INTAB0 -- TABULATE ON SCREEN
INTAB0:
       MOV     A,C     ; GET CHAR CNT
       ANI     7       ; MASK FOR DIFFERENCE FROM 8
       MOV     B,A     ; STORE IN REG B TEMPORARILY
       MVI     A,8     ; SUBTRACT FROM 8
       SUB     B
       MOV     B,A     ; <SP> COUNT IN B
       ADD     C       ; ADD TO CHAR COUNT
       MOV     C,A
       LDA     ECHO    ; ECHO ON?
       ORA     A       ; 0=NO
       RZ
       MVI     A,' '   ; <SP> IN A
INTAB1:
       CALL    COUT    ; PRINT <SP>
       DCR     B       ; COUNT DOWN
       JNZ     INTAB1
       RET

;
;  ASCII SPECIAL CHARACTER EQUATES
;
NULL    EQU      0      ; NULL
BEL     EQU      7      ; BELL
BS      EQU      8      ; BACKSPACE
TAB     EQU      9      ; TAB
LF      EQU     10      ; LINE FEED
CR      EQU     13      ; CARRIAGE RETURN
CTRLE   EQU     'E'-40H ; CTRL-E
CTRLR   EQU     'R'-40H ; CTRL-R
CTRLU   EQU     'U'-40H ; CTRL-U
CTRLX   EQU     'X'-40H ; CTRL-X
DEL     EQU     7FH     ; DELETE CHAR

       END