;       SCCSID = @(#)strin.asm  1.2 85/04/18
Break

 assume nocheck, ss:DOSGROUP

; Inputs:
;       DS:DX Point to an input buffer
; Function:
;       Fill buffer from console input until CR
; Returns:
;       None

        procedure   D_STD_CON_STRING_INPUT,NEAR   ;System call 10
ASSUME  DS:NOTHING,ES:NOTHING

        MOV     AX,SS
        MOV     ES,AX
 assume es:DOSGROUP
        MOV     SI,DX
        XOR     CH,CH
        LODSW
;
; AL is the buffer length
; AH is the template length
;
        OR      AL,AL
        retz                    ;Buffer is 0 length!!?
        MOV     BL,AH           ;Init template counter
        MOV     BH,CH           ;Init template counter
 ;
 ; BL is the number of bytes in the template
 ;
        CMP     AL,BL
        JBE     NOEDIT          ;If length of buffer inconsistent with contents
        CMP     BYTE PTR [BX+SI],c_CR
        JZ      EDITON          ;If CR correctly placed EDIT is OK
;
; The number of chars in the template is >= the number of chars in buffer or
; there is no CR at the end of the template.  This is an inconsistant state
; of affairs.  Pretend that the template was empty:
;
NOEDIT:
        MOV     BL,CH           ;Reset buffer
EDITON:
        MOV     DL,AL
        DEC     DX              ;DL is # of bytes we can put in the buffer
;
; Top level.  We begin to read a line in.
;
NEWLIN:
        MOV     AL,[ss:CARPOS]
        MOV     [ss:STARTPOS],AL   ;Remember position in raw buffer
        PUSH    SI
        MOV     DI,OFFSET INBUF wrt DOSGROUP        ;Build the new line here
        MOV     [ss:INSMODE],CH    ;Insert mode off
        MOV     BH,CH           ;No chars from template yet
        MOV     DH,CH           ;No chars to new line yet
        invoke  D_STD_CON_INPUT_NO_ECHO          ;Get first char
        CMP     AL,c_LF         ;Linefeed
        JNZ     GOTCH           ;Filter out LF so < works
;
; This is the main loop of reading in a character and processing it.
;
;   BH is the index of the next byte in the template
;   BL is the length of the template
;   DH is the number of bytes in the buffer
;   DL is the length of the buffer
;
entry   GETCH
        invoke  D_STD_CON_INPUT_NO_ECHO
GOTCH:
;
; Brain-damaged TP ignored ^F in case his BIOS did not flush the
; input queue.
;
        CMP     AL,"F"-"@"
        JZ      GETCH
;
; If the leading char is the function-key lead byte
;
ESCCHAR equ EscChar	; NASM port label
        CMP     AL,[ss:ESCCHAR]
        JZ      ESCape          ;change reserved keyword DBM 5-7-87
;
; Rubout and ^H are both destructive backspaces.
;
        CMP     AL,c_DEL
        JZ      BACKSPJ
        CMP     AL,c_BS
        JZ      BACKSPJ
;
; ^W deletes backward once and then backs up until a letter is before the
; cursor
;
        CMP     AL,"W" - "@"
; The removal of the comment characters before the jump statement will
; cause ^W to backup a word.
;***    JZ      WordDel
        NOP
        NOP
        CMP     AL,"U" - "@"
; The removal of the comment characters before the jump statement will
; cause ^U to clear a line.
;***    JZ      LineDel
        NOP
        NOP

;
; CR terminates the line.
;
        CMP     AL,c_CR
        JZ      ENDLIN
;
; LF goes to a new line and keeps on reading.
;
        CMP     AL,c_LF
        JZ      PHYCRLF
;
; ^X (or ESC) deletes the line and starts over
;
CANCHAR equ CanChar	; NASM port label
        CMP     AL,[ss:CANCHAR]
        JZ      KILNEW
;
; Otherwise, we save the input character.
;
SAVCH:
        CMP     DH,DL
        JAE     BUFFUL                  ; buffer is full.
        STOSB
        INC     DH                      ; increment count in buffer.
        invoke  BUFOUT                  ;Print control chars nicely
        CMP     BYTE PTR [ss:INSMODE],0
        JNZ     GETCH                   ; insertmode => don't advance template
        CMP     BH,BL
        JAE     GETCH                   ; no more characters in template
        INC     SI                      ; Skip to next char in template
        INC     BH                      ; remember position in template
        JMP     SHORT GETCH

BACKSP equ BackSp	; NASM port label
BACKSPJ: JMP    SHORT BACKSP

BUFFUL:
        MOV     AL,7                    ; Bell to signal full buffer
        invoke  OUTT
        JMP     SHORT GETCH

ESCape:                         ;change reserved keyword DBM 5-7-87
        transfer    OEMFunctionKey      ; let the OEM's handle the key dispatch

ENDLIN:
        STOSB                           ; Put the CR in the buffer
        invoke  OUTT                    ; Echo it
        POP     DI                      ; Get start of user buffer
        MOV     [DI-1],DH               ; Tell user how many bytes
        INC     DH                      ; DH is length including CR
entry COPYNEW
        SaveReg <DS,ES>
        RestoreReg <DS,ES>              ; XCHG ES,DS
        MOV     SI,OFFSET INBUF wrt DOSGROUP
        MOV     CL,DH                   ; set up count
        REP     MOVSB                   ; Copy final line to user buffer
        return
;
; Output a CRLF to the user screen and do NOT store it into the buffer
;
PHYCRLF:
        invoke  CRLF
        JMP     GETCH

;
; Delete the previous line
;
LineDel:
        OR      DH,DH
GetCh equ GETCH	; NASM port label
        JZ      GetCh
        Call    BackSpace
        JMP     LineDel

;
; delete the previous word.
;
WordDel:
WordLoop:
        Call    BackSpace               ; backspace the one spot
        OR      DH,DH
        JZ      GetChJ
        MOV     AL,[ES:DI-1]
        cmp     al,'0'
GetChj equ GetChJ	; NASM port label
        jb      GetChj
        cmp     al,'9'
        jbe     WordLoop
        OR      AL,20h
        CMP     AL,'a'
        JB      GetChJ
        CMP     AL,'z'
        JBE     WordLoop
GetChJ:
        JMP     GetCh
;
; The user wants to throw away what he's typed in and wants to start over.  We
; print the backslash and then go to the next line and tab to the correct spot
; to begin the buffered input.
;
        entry   KILNEW
        MOV     AL,"\"
        invoke  OUTT            ;Print the CANCEL indicator
        POP     SI              ;Remember start of edit buffer
PUTNEW:
        invoke  CRLF            ;Go to next line on screen
        MOV     AL,[ss:STARTPOS]
        invoke  TAB             ;Tab over
        JMP     NEWLIN          ;Start over again


;
; Destructively back up one character position
;
entry   BackSp
        Call    BackSpace
        JMP     GetCh

BackSpace:
        OR      DH,DH
        JZ      OLDBAK          ;No chars in line, do nothing to line
        CALL    BACKUP          ;Do the backup
        MOV     AL,[ES:DI]      ;Get the deleted char
        CMP     AL," "
        JAE     OLDBAK          ;Was a normal char
        CMP     AL,c_HT
        JZ      BAKTAB          ;Was a tab, fix up users display
;; 9/27/86 fix for ctrl-U backspace
        CMP     AL,"U"-"@"      ; ctrl-U is a section symbol not ^U
        JZ      OLDBAK
        CMP     AL,"T"-"@"      ; ctrl-T is a paragraphs symbol not ^T
        JZ      OLDBAK
;; 9/27/86 fix for ctrl-U backspace
        CALL    BACKMES         ;Was a control char, zap the '^'
OLDBAK:
        CMP     BYTE PTR [ss:INSMODE],0
        retnz                   ;In insert mode, done
        OR      BH,BH
        retz                    ;Not advanced in template, stay where we are
        DEC     BH              ;Go back in template
        DEC     SI
        return

BAKTAB:
        PUSH    DI
        DEC     DI              ;Back up one char
        STD                     ;Go backward
        MOV     CL,DH           ;Number of chars currently in line
        MOV     AL," "
        PUSH    BX
        MOV     BL,7            ;Max
        JCXZ    FIGTAB          ;At start, do nothing
FNDPOS:
        SCASB                   ;Look back
        JNA     CHKCNT
        CMP     BYTE PTR [ES:DI+1],9
        JZ      HAVTAB          ;Found a tab
        DEC     BL              ;Back one char if non tab control char
CHKCNT:
        LOOP    FNDPOS
FIGTAB:
        SUB     BL,[ss:STARTPOS]
HAVTAB:
        SUB     BL,DH
        ADD     CL,BL
        AND     CL,7            ;CX has correct number to erase
        CLD                     ;Back to normal
        POP     BX
        POP     DI
        JZ      OLDBAK          ;Nothing to erase
TABBAK:
        invoke  BACKMES
        LOOP    TABBAK          ;Erase correct number of chars
        JMP     SHORT OLDBAK

BACKUP:
        DEC     DH              ;Back up in line
        DEC     DI
BACKMES:
        MOV     AL,c_BS         ;Backspace
        invoke  OUTT
        MOV     AL," "          ;Erase
        invoke  OUTT
        MOV     AL,c_BS         ;Backspace
        JMP     OUTT            ;Done

;User really wants an ESC character in his line
        entry   TwoEsc
        MOV     AL,[ss:ESCCHAR]
        JMP     SAVCH

;Copy the rest of the template
        entry   COPYLIN
        MOV     CL,BL           ;Total size of template
        SUB     CL,BH           ;Minus position in template, is number to move
        JMP     SHORT COPYEACH

        entry   CopyStr
        invoke  FINDOLD         ;Find the char
        JMP     SHORT COPYEACH  ;Copy up to it

;Copy one char from template to line
        entry   COPYONE
        MOV     CL,1
;Copy CX chars from template to line
COPYEACH:
        MOV     BYTE PTR [ss:INSMODE],0    ;All copies turn off insert mode
        CMP     DH,DL
        JZ      GETCH2                  ;At end of line, can't do anything
        CMP     BH,BL
        JZ      GETCH2                  ;At end of template, can't do anything
        LODSB
        STOSB
        invoke  BUFOUT
        INC     BH                      ;Ahead in template
        INC     DH                      ;Ahead in line
        LOOP    COPYEACH
GETCH2:
        JMP     GETCH

;Skip one char in template
        entry   SKIPONE
        CMP     BH,BL
        JZ      GETCH2                  ;At end of template
        INC     BH                      ;Ahead in template
        INC     SI
        JMP     GETCH

        entry   SKIPSTR
        invoke  FINDOLD                 ;Find out how far to go
        ADD     SI,CX                   ;Go there
        ADD     BH,CL
        JMP     GETCH

;Get the next user char, and look ahead in template for a match
;CX indicates how many chars to skip to get there on output
;NOTE: WARNING: If the operation cannot be done, the return
;       address is popped off and a jump to GETCH is taken.
;       Make sure nothing extra on stack when this routine
;       is called!!! (no PUSHes before calling it).
FINDOLD:
        invoke  D_STD_CON_INPUT_NO_ECHO
        CMP     AL,[ss:ESCCHAR]            ; did he type a function key?
        JNZ     FindSetup               ; no, set up for scan
        invoke  D_STD_CON_INPUT_NO_ECHO  ; eat next char
NotFnd equ NOTFND	; NASM port label
        JMP     NotFnd                  ; go try again
	nop	; identicalise
FindSetup:
        MOV     CL,BL
        SUB     CL,BH           ;CX is number of chars to end of template
        JZ      NOTFND          ;At end of template
        DEC     CX              ;Cannot point past end, limit search
        JZ      NOTFND          ;If only one char in template, forget it
        PUSH    ES
        PUSH    DS
        POP     ES
 assume es:nothing
        PUSH    DI
        MOV     DI,SI           ;Template to ES:DI
        INC     DI
        REPNE   SCASB           ;Look
        POP     DI
        POP     ES
 assume es:nothing
        JNZ     NOTFND          ;Didn't find the char
        NOT     CL              ;Turn how far to go into how far we went
        ADD     CL,BL           ;Add size of template
        SUB     CL,BH           ;Subtract current pos, result distance to skip
        return

NOTFND:
        POP     BP              ;Chuck return address
        JMP     GETCH

entry   REEDIT
        MOV     AL,"@"          ;Output re-edit character
        invoke  OUTT
        POP     DI
        PUSH    DI
        PUSH    ES
        PUSH    DS
        invoke  COPYNEW         ;Copy current line into template
        POP     DS
 assume ds:nothing
        POP     ES
 assume es:nothing
        POP     SI
        MOV     BL,DH           ;Size of line is new size template
        JMP     PUTNEW          ;Start over again

        entry   EXITINS
        entry   ENTERINS
        NOT     BYTE PTR [ss:INSMODE]
        JMP     GETCH

;Put a real live ^Z in the buffer (embedded)
        entry   CTRLZ
        MOV     AL,"Z"-"@"
        JMP     SAVCH

;Output a CRLF
        entry   CRLF
        MOV     AL,c_CR
        invoke  OUTT
        MOV     AL,c_LF
        JMP     OUTT

EndProc D_STD_CON_STRING_INPUT

