
CR EQU 0DH
LF EQU 0AH

BS EQU 8D
ENTER EQU 13D
ESCAPE EQU 27D
SPC EQU 20H
TAB EQU 9H
MAX_STR_LENGTH EQU 255D
MAX_LINE       EQU (32*1024)/MAX_STR_LENGTH

;-----------------------------------------------------------------
; * this function moves cursor to the position of (CUR_X,CUR_Y)
; * (left,top) is (0,0) 
; CUR_X : current x position
; CUR_Y : current y position
;-----------------------------------------------------------------
SET_CURSOR MACRO
           PUSH DX
           PUSH BX
           PUSH AX
     
           XOR BX,BX
           MOV DH,CUR_Y
           MOV DL,CUR_X
           MOV AH,2H
           INT 10H

           POP AX
           POP BX
           POP DX
           ENDM

;---------------------------------------------------------------
; * hide cursor
;---------------------------------------------------------------
HIDE_CURSOR MACRO
           PUSH AX
           PUSH CX
           MOV AH,1
           MOV CL,CH
           INT 10H
           POP CX
           POP AX
           ENDM

;---------------------------------------------------------------
; * show cursor
;---------------------------------------------------------------
SHOW_CURSOR MACRO
            PUSH AX
            PUSH CX
            MOV AH,1
            MOV CH,14
            MOV CL,16
            INT 10H
            POP CX
            POP AX
            ENDM


;---------------------------------------------------------------
; * update LINE_END information
; CUR_X  : current x position. (leftest position is 1)
; CUR_Y  : current y position. (top position is 2)
; CURLINE : current line position. (initially 22D)
; LINE_END : information of end of line
;---------------------------------------------------------------
PUT_LINE_END MACRO
LOCAL NOT_UPDATE
             PUSH AX
             PUSH BX
             
             XOR AH,AH
             MOV BX,OFFSET LINE_END
             MOV AL,CUR_Y
             SUB AL,2H
             ADD AL,CURLINE
             SUB AL,22D

             ADD BX,AX
             MOV AL,CUR_X
             ADD AL,CURLEFT
             DEC AL ; line end = 0~254 => x position = 1~255
             CMP AL,[BX]
             JBE NOT_UPDATE
             MOV [BX],AL
             
NOT_UPDATE : POP BX
             POP AX
             ENDM
             

;------------------------------------------------------------
; * get LINE_END of specified line
; CUR_Y , CURLINE: line num to get LINE_END information
; - AL : return LINE_END information
;------------------------------------------------------------
GET_LINE_END MACRO
             PUSH BX
             MOV BX,OFFSET LINE_END
             MOV AL,CUR_Y
             SUB AL,2H ; top of screen is 2
             ADD AL,CURLINE
             SUB AL,22D

             XLATB
             POP BX
             ENDM


;-----------------------------------------------------------------
; * print <ins> state
; * print current x,y position
;-----------------------------------------------------------------
LAST_LINE MACRO
LOCAL NOT_INS,LINE_FILL
          PUSH AX
          PUSH BX
          PUSH CX
          PUSH DX
          PUSH SI          

          MOV AH,CUR_X
          PUSH AX
          MOV AL,CUR_Y
          PUSH AX

          MOV CX,80
          MOV CUR_X,0
          MOV CUR_Y,24
          MOV DL,' '
          MOV ATTR,33H

LINE_FILL:CALL PUT_CHAR
          LOOP LINE_FILL
          
          MOV ATTR,30H  ; print FILENAME
          MOV CUR_X,3
          MOV SI,OFFSET FILENAME
          CALL PUT_STRING
          
          MOV BL,AH ; X=CURLEFT+CURX
          ADD BL,CURLEFT
          MOV CL,AL ; Y=(CUR_Y-1)+(CURLINE-22)
          ADD CL,CURLINE
          SUB CL,22
          DEC CL 
          MOV BH,ATTR

          MOV CUR_X,70
          MOV CUR_Y,24

          MOV ATTR,30H
          MOV DL,'?
          CALL PUT_CHAR
          MOV DL,' '
          CALL PUT_CHAR
          XOR AH,AH
          MOV AL,BL
          MOV DL,10D
          DIV DL
          PUSH AX 
          XOR AH,AH
          DIV DL
          PUSH AX
          MOV DL,AL
          ADD DL,30H
          CALL PUT_CHAR
          POP DX
          MOV DL,DH
          ADD DL,30H
          CALL PUT_CHAR
          POP DX
          MOV DL,DH
          ADD DL,30H
          CALL PUT_CHAR
          
          XOR AH,AH
          MOV DL,':'
          CALL PUT_CHAR
          MOV AL,CL
          MOV DL,10D
          DIV DL
          PUSH AX 
          XOR AH,AH
          DIV DL
          PUSH AX
          MOV DL,AL
          ADD DL,30H
          CALL PUT_CHAR
          POP DX
          MOV DL,DH
          ADD DL,30H
          CALL PUT_CHAR
          POP DX
          MOV DL,DH
          ADD DL,30H
          CALL PUT_CHAR

          CMP INS,1H
          JNZ NOT_INS
          MOV CUR_X,65
          MOV ATTR,3FH
          MOV SI,OFFSET INS_MSG
          CALL PUT_STRING
          
 NOT_INS: POP AX
          MOV CUR_Y,AL
          POP AX
          MOV CUR_X,AH

          POP SI
          POP DX
          POP CX
          POP BX
          POP AX
          ENDM

;--------------------------------------------------------------------
; * make BLACK LINE at last line
;--------------------------------------------------------------------
BLACK_LINE MACRO
LOCAL LINE_FILL           
           PUSH CX
           PUSH DX
           MOV AH,CUR_X
           MOV AL,CUR_Y
           PUSH AX
           MOV CX,80
           MOV CUR_X,0
           MOV CUR_Y,24
           MOV DL,' '
           MOV ATTR,70H

LINE_FILL: CALL PUT_CHAR
           LOOP LINE_FILL
           POP AX
           MOV CUR_X,AH
           MOV CUR_Y,AL
           POP DX
           POP CX
           ENDM

;----------------------------------------------------------------------
; * print MAX_SPC_ERR
; * use when maximum line exceed or maximum column exceed.
;----------------------------------------------------------------------
MAX_ERR MACRO
        PUSH AX
        PUSH SI
        BLACK_LINE
        MOV AL,CUR_X
        MOV AH,CUR_Y
        MOV CUR_X,10
        MOV CUR_Y,24
        MOV SI,OFFSET MAX_SPC_ERR
        MOV ATTR,70H
        CALL PUT_STRING
        MOV CUR_X,AL
        MOV CUR_Y,AH
        CALL READ_KEY
        POP SI
        POP AX
        ENDM

;----------------------------------------------------------------------
; * print FILE ERR
; * use when carry during open/save
;----------------------------------------------------------------------
FP_ERR MACRO
        PUSH AX
        PUSH CX
        PUSH SI
        PUSH DI
        PUSH ES

        BLACK_LINE
        MOV AL,CUR_X
        MOV AH,CUR_Y
        MOV CUR_X,10
        MOV CUR_Y,24
        LEA SI,FILE_ERR
        MOV ATTR,70H
        CALL PUT_STRING
        MOV CUR_X,AL
        MOV CUR_Y,AH
        CALL READ_KEY
        
        MOV AX,DATA
        MOV ES,AX
        LEA SI,BACKUP_FP
        LEA DI,FILENAME
        MOV CX,14D
        REP MOVSB
        
        POP ES
        POP DI
        POP SI
        POP CX
        POP AX
        ENDM

;--------------------------------------------------------------------------
; * save BACKUP_FP
; * COPY FILENAME to BACKUP_FP when writing has been succeed.
; BACKUP_FP : used when write or open is failed.
; FILENAME  : original file name
;--------------------------------------------------------------------------
FILE_TO_BACK MACRO
             PUSH AX
             PUSH CX
             PUSH SI
             PUSH DI
             PUSH ES

             MOV AX,DATA
             MOV ES,AX

             LEA SI,FILENAME
             LEA DI,BACKUP_FP
             MOV CX,14D
             REP MOVSB

             POP ES
             POP DI
             POP SI
             POP CX
             POP AX
             ENDM


;-------------------------------------------------------------------------
; * get proper offset from TEXT
; * calculate SI
; CURLINE : current bottom line
; CUR_Y   : current y position
; - SI : offset from TEXT
;        SI=OFFSET TEXT + (CURLINE-22)+(CUR_Y-2) * MAX_STR_LENGTH
;--------------------------------------------------------------------------
CALC_SI MACRO
LOCAL ADD_MAX,END_CALC_SI
        PUSH AX
        MOV SI,OFFSET TEXT
        MOV AL,CURLINE
        SUB AL,22
        ADD AL,CUR_Y
        SUB AL,2
ADD_MAX:OR AL,AL
        JZ END_CALC_SI
        ADD SI,MAX_STR_LENGTH
        DEC AL
        JMP ADD_MAX
END_CALC_SI:
        POP AX
        ENDM

DATA SEGMENT
    TEXT    DB 32D*1024D DUP(' ') ; text : 32KB
    INS     DB 0H
    CUR_X   DB 0H
    CUR_Y   DB 0H
    CURLINE DB 22D
    CURLEFT DB 0H
    COUNT_X DB ?
    COUNT_Y DB ?
    LINE_END DB MAX_LINE DUP(0H)
    EOF     DB 0H 
    ATTR    DB 0H
    FILENAME DB 'NONAME00.TXT',0,'$'
    BACKUP_FP DB 'NONAME00.TXT',0,'$'
    NEW_NAME DB 'NONAME00.TXT',0,'$'
    TEMP    DB 13D
            DB 20D DUP(?)
    CR_LF   DB CR,LF
    TOP     DB ?
    BOTTOM  DB ?
    MENU    DB '   NEW[F1]    OPEN[F2]     SAVE[F3]    SAVE AS...[F4]    FIND[F5]    EXIT[F6]   $'
    NAME_MSG DB ' 9731256  Seo, Min-Koo$'
    NEW_MSG DB ' Do you really want new? (Y/N)$'
    SAVED_MSG DB ' File saved. Hit any key$'
    LOADED_MSG DB ' File loaded. Hit any key$'
    FILE_MSG DB ' FILENAME :$'
    EXIT_MSG DB ' Want EXIT? (Y/N)$'
    FILE_ERR DB ' There was a FILE ERROR. Hit any key.$'
    MAX_SPC_ERR DB ' Maximum space exceeded. Hit any key.$'
    IF_ERR_1 DB 0
    INS_MSG DB '<INS>$'
DATA ENDS

STACK SEGMENT STACK
   DW 100H DUP(?)
STACK ENDS

CODE SEGMENT PUBLIC 'CODE'
 ASSUME CS:CODE,DS:DATA,SS:STACK
 PROGSTART: MOV AX,DATA
            MOV DS,AX
            CALL INIT_SCR
            CALL READ_STRING
            MOV AX,4C00H
            INT 21H



;------------------------------------------------------------
; * print string in the screen from (CUR_X,CUR_Y)
; ATTR  : attribute of characters
; SI    : offset of string to print. string is followed by $
; CUR_X : column position
; CUR_Y : line position
;------------------------------------------------------------
PUT_STRING PROC NEAR
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH ES
            
            MOV AX,0B800H
            MOV ES,AX

            XOR AX,AX
            MOV AL,CUR_Y ; 2(character+attr)*80(character)
            MOV CL,160D
            MUL CL
            MOV BX,AX
            
            MOV AL,CUR_X   ; 2(character+attr)
            MOV CL,2D
            MUL CL
            ADD BX,AX

            MOV AH,ATTR
NEXT_PUT  : LODSB
            CMP AL,'$'
            JZ END_PUT_STRING
            MOV ES:[BX],AX
            INC BX
            INC BX
            JMP NEXT_PUT

END_PUT_STRING: 
            POP ES
            POP CX
            POP BX
            POP AX
            RET
PUT_STRING ENDP             

;-------------------------------------------------------------
; * put character in the location of (CUR_X,CUR_Y)
; ATTR    : attribute of character
; DL    : byte to print on screen
; CUR_X : column position   
; CUR_Y : line position
;-------------------------------------------------------------
PUT_CHAR PROC NEAR
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH ES
            
            MOV AX,0B800H
            MOV ES,AX

            XOR AX,AX
            MOV AL,CUR_Y ; 2(character+attr)*80(character)
            MOV CL,160D
            MUL CL
            MOV BX,AX
            
            MOV AL,CUR_X   ; 2(character+attr)
            MOV CL,2D
            MUL CL
            ADD BX,AX

            MOV DH,ATTR
            MOV ES:[BX],DX
            INC CUR_X            
            POP ES
            POP CX
            POP BX
            POP AX
            RET
PUT_CHAR ENDP

;--------------------------------------------------------------------
; * clear the screen from top to bottom
; ATTR   : used as color
; TOP    : top 
; BOTTOM : bottom
;--------------------------------------------------------------------
CLEAR_SCR PROC NEAR
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH ES

            MOV AX,0B800H
            MOV ES,AX
            
            XOR AX,AX
            MOV AL,TOP ; 2(character+attr)*80(character)
            MOV CL,160D
            MUL CL
            MOV BX,AX
            
            MOV DH,ATTR
            MOV DL,' '
LINE_AGN  : MOV CX,79
LINE_CLEAR: MOV ES:[BX],DX
            INC BX
            INC BX
            LOOP LINE_CLEAR
            INC TOP
            MOV AL,TOP
            CMP AL,BOTTOM
            JBE LINE_AGN
            
            POP ES
            POP CX
            POP BX
            POP AX
            RET
CLEAR_SCR ENDP       


;-----------------------------------------------------------------
; * clear screen and print menu,ins key and etc.
;-----------------------------------------------------------------
INIT_SCR  PROC NEAR
             PUSH AX
             PUSH BX
             PUSH CX
             PUSH DX

             MOV TOP,0
             MOV BOTTOM,24
             MOV ATTR,0H
             CALL CLEAR_SCR

             MOV ATTR,17H
             MOV TOP,1
             MOV BOTTOM,24
             CALL CLEAR_SCR

             MOV ATTR,70H
             MOV SI,OFFSET MENU
             CALL PUT_STRING
             
             MOV ATTR,17H
             MOV CUR_X,0
             MOV CUR_Y,1
             MOV DL,'?
             CALL PUT_CHAR
             MOV CUR_X,79
             MOV DL,'?
             CALL PUT_CHAR
             MOV CUR_X,0
             MOV CUR_Y,23
             MOV DL,'?
             CALL PUT_CHAR
             MOV CUR_X,79
             MOV DL,'?
             CALL PUT_CHAR
             
             
             MOV CUR_X,1
             MOV CUR_Y,1
             MOV DL,'?
             MOV CX,78
  HORZ_LINE :CALL PUT_CHAR
             DEC CUR_X
             MOV CUR_Y,23
             CALL PUT_CHAR
             MOV CUR_Y,1
             LOOP HORZ_LINE
             
             MOV CX,21
             MOV CUR_Y,2
  VERT_LINE: MOV CUR_X,0
             MOV DL,'?
             CALL PUT_CHAR
             MOV CUR_X,79
             CALL PUT_CHAR
             INC CUR_Y
             LOOP VERT_LINE
             
             LAST_LINE
             MOV CUR_X,1
             MOV CUR_Y,24
             MOV ATTR,3FH
             MOV SI,OFFSET NAME_MSG
             CALL PUT_STRING
             MOV CUR_X,1
             MOV CUR_Y,2
             SET_CURSOR
             POP DX
             POP CX
             POP BX
             POP AX
             RET
INIT_SCR ENDP
;-----------------------------------------------------------
; * update CURLINE,EOF and CUR_Y
; MAX_LINE : 32*1024(32KB) / MAX_STR_LENGTH
;            maximum line num of TEXT
; CURLINE : current line num
; EOF     : end of line num of file
; - IF_ERR_1 : on maximum line exceeded IF_ERR_1=1
;----------------------------------------------------------
EOF_CURLINE_CUR_Y  PROC NEAR
                 PUSH AX
                 CMP CUR_Y,1    ; check up arrow
                 JNE NOT_DEC_CUR
                 CMP CURLINE,22
                 JE FIRST_SCR
                 MOV CUR_Y,2
                 DEC CURLINE
                 CALL PAINT_SCR
                 JMP NOT_DEC_CUR
   FIRST_SCR   : MOV CUR_Y,2
   NOT_DEC_CUR : CMP CUR_Y,23  ; check down arrow
                 JNE NOT_INC_CUR
                 INC CURLINE
                 MOV CUR_Y,22
                 CALL PAINT_SCR
   NOT_INC_CUR : MOV AL,CURLINE
                 SUB AL,22
                 ADD AL,CUR_Y
                 SUB AL,2
                 CMP AL,EOF  ; check EOF >= (CURLINE-22)+(CUR_Y-2)
                 JBE NOT_INC_EOF
                 MOV EOF,AL
   NOT_INC_EOF : CMP EOF,MAX_LINE 
                 JB  NOT_MAX_LINE
                 DEC EOF
                 DEC CURLINE
                 MAX_ERR
                 MOV IF_ERR_1,1
   NOT_MAX_LINE: POP AX
EOF_CURLINE_CUR_Y  ENDP

;-------------------------------------------------------------------
; * repaint screen ( print out TEXT in the screen )
; * if CUR_X > 78 or CUR_X<1 then repaint (78D right of screen)
; * if CUR_Y > 22 or CUR_Y<2 then repaint (22D bottom of screen)
; * if CURLINE is bigger than MAX_LINE then 
; * if repaint, change some variables which are listed below
; CURLINE : line num of bottom of screen
; CURLEFT : X counter of leftest column
;           so, real column to be printed out in the last line is
;           CURLEFT+CUR_X
;-------------------------------------------------------------------
PAINT_SCR PROC NEAR
            PUSH AX
            PUSH BX
            PUSH CX
            PUSH DX
            PUSH SI

            HIDE_CURSOR

            MOV AL,CUR_X
            PUSH AX
            MOV AL,CUR_Y
            PUSH AX

            MOV ATTR,17H
            MOV CUR_X,1
            MOV CUR_Y,2

            MOV BX,OFFSET TEXT
            MOV AL,CURLINE
            SUB AL,22
   CONT_ADD:OR AL,AL   ; get proper address of text
            JZ END_ADD
            ADD BX,MAX_STR_LENGTH
            DEC AL
            JMP CONT_ADD
          

   END_ADD: MOV CL,0D ; cl contains line num
            
            XOR AH,AH
            MOV AL,CURLEFT
            MOV SI,AX
PRINT_LINE: MOV DL,[BX+SI]   ; screen is 78*22
            CALL PUT_CHAR
            INC SI
            CMP SI,MAX_STR_LENGTH
            JE EOL
            CMP CUR_X,78
            JBE PRINT_LINE
 EOL:       INC CL
            CMP CL,20
            JA END_PAINT_SCR
            MOV CUR_X,1
            INC CUR_Y
            ADD BX,MAX_STR_LENGTH
            MOV SI,AX
            JMP PRINT_LINE

END_PAINT_SCR: SHOW_CURSOR
   
               POP AX
               MOV CUR_Y,AL
               POP AX
               MOV CUR_X,AL

               POP SI
               POP DX
               POP CX
               POP BX
               POP AX
               RET
PAINT_SCR ENDP

;------------------------------------------------------------------
; * input keys and repaint screen when needed
; * BX+SI : current position of table
; * BX : OFFSET IN THE STRING
; * SI : START OF TABLE
; * ATTR  : attribute of characters
; TEXT  : offset of input table
; CUR_X : x position
; CUR_Y : y position
;------------------------------------------------------------------
READ_STRING PROC NEAR
             
             MOV SI,OFFSET TEXT
             MOV BX,0H
             
 CHAR_AGN :  LAST_LINE
             SET_CURSOR
             CALL READ_KEY
             SET_CURSOR
             CMP AH,59
             JNE NOT_F1
             CALL NEW_TEXT ; F1
             JMP CHAR_AGN
     NOT_F1 :CMP AH,60
             JNE NOT_F2
             CALL GIVE_FILE
             CALL LOAD_FILE ; F2
             JMP CHAR_AGN
     NOT_F2 :CMP AH,61
             JNE NOT_F3
             CALL SAVE_FILE ; F3
             JMP CHAR_AGN
     NOT_F3 :CMP AH,62
             JNE NOT_F4
             CALL GIVE_FILE ; F4
             CALL SAVE_FILE
             JMP CHAR_AGN
     NOT_F4 :CMP AH,63
             JNE NOT_F5
            ;CALL FIND ; F5
             JMP CHAR_AGN
     NOT_F5 :CMP AH,64
             JNE NOT_FUNCKEY
             CALL EXIT ; F6
             JMP CHAR_AGN

NOT_FUNCKEY :MOV ATTR,17H
             CMP AH,75  ; left arrow
             JE LEFT   
             CMP AH,77  ; right arrow
             JE RIGHT
             CMP AH,72  ; up arrow
             JE UP
             CMP AH,80  ; down arrow
             JE DOWN
             CMP AH,79  ; end key
             JE END_KEY
             CMP AH,71  ; home key
             JE HOME_KEY
             CMP AH,73  ; page up
             JE PAGE_UP
             CMP AH,81  ; page down
             JE PAGE_DOWN
             CMP AL,ENTER
             JE ENTER_KEY ; enter key
             CMP AL,BS
             JNE NOT_BS
             CALL BACK_SPACE ; back space
             JMP CHAR_AGN
             
    NOT_BS : CMP AL,TAB
             JE TAB_KEY ; tab key
             CMP AL,ESCAPE
             JE FLUSH_BUF ; esc key
             CMP BX,MAX_STR_LENGTH-1
             JB NORM_KEY
             MAX_ERR
             JMP CHAR_AGN

                                          

    NORM_KEY: MOV [SI+BX],AL ; normal key input
              INC BX
              INC CUR_X
              PUT_LINE_END
              CMP CUR_X,79
              JNE NOT_SCROLL
              MOV CUR_X,78
              INC CURLEFT
              CALL PAINT_SCR
              JMP CHAR_AGN
 NOT_SCROLL : MOV DL,AL
              DEC CUR_X ; CUR_X++ in PUT_CHAR
              CALL PUT_CHAR
              JMP CHAR_AGN
 
 LEFT      : OR BX,BX
             JZ CHAR_AGN
             DEC BX
             DEC CUR_X
             CMP CUR_X,0
             JNE CHAR_AGN
             DEC CURLEFT
             MOV CUR_X,1
             CALL PAINT_SCR
             JMP CHAR_AGN

 RIGHT     : MOV AL,CUR_X
             ADD AL,CURLEFT
             CMP AL,MAX_STR_LENGTH ; check maximum column
             JNE DO_RIGHT
             MAX_ERR
             JMP CHAR_AGN

   DO_RIGHT: INC BX
             INC CUR_X
             CMP CUR_X,79
             JNE CHAR_AGN
             MOV CUR_X,78
             INC CURLEFT
             CALL PAINT_SCR
             JMP CHAR_AGN

 UP        : DEC CUR_Y
             CALL EOF_CURLINE_CUR_Y
             CALC_SI
             JMP CHAR_AGN

 DOWN      : INC CUR_Y
             CALL EOF_CURLINE_CUR_Y
             CALC_SI
             MOV IF_ERR_1,0
             JMP CHAR_AGN
             
 PAGE_UP   : MOV CX,21
     UPING : DEC CUR_Y
             CALL EOF_CURLINE_CUR_Y
             LOOP UPING
             CALC_SI
             JMP CHAR_AGN

 PAGE_DOWN : MOV CX,21
   DOWNING : INC CUR_Y
             CALL EOF_CURLINE_CUR_Y
             CMP IF_ERR_1,1
             JE END_DOWNING
             LOOP DOWNING
END_DOWNING: MOV IF_ERR_1,0
             CALC_SI
             JMP CHAR_AGN

 END_KEY   :  GET_LINE_END
              INC AL ; 0~254 => 1~255
              SUB AL,CURLEFT
              CMP AL,78     ; end of string is in the screen
              JA CHANGE_SCR
              CMP AL,0
              JB CHANGE_SCR
              MOV CUR_X,AL ; CUR_X = AL - CURLEFT
              JMP GIVE_BX
 CHANGE_SCR : GET_LINE_END
              CMP AL,10D
              JB NO_CURLEFT
              SUB AL,10D
              MOV CURLEFT,AL
              MOV CUR_X,10
              CALL PAINT_SCR
              JMP GIVE_BX
 NO_CURLEFT : MOV CURLEFT,0
              MOV CUR_X,AL
              CALL PAINT_SCR
  GIVE_BX :   GET_LINE_END
              XOR AH,AH
              MOV BX,AX
              JMP CHAR_AGN
 
 HOME_KEY  : MOV BX,0H
             MOV CUR_X,1
             MOV CURLEFT,0
             CALL PAINT_SCR
             JMP CHAR_AGN

 TAB_KEY   :MOV CX,8H

    TAB_LOOP : MOV AL,CUR_X
               ADD AL,CURLEFT
               CMP AL,MAX_STR_LENGTH ; check maximum column
               JNE DO_TAB
               MAX_ERR
               JMP CHAR_AGN

      DO_TAB : INC BX
               INC CUR_X
               CMP CUR_X,79
               JNE TAB_LOOP_END
               MOV CUR_X,78
               INC CURLEFT
               CALL PAINT_SCR
TAB_LOOP_END : LOOP TAB_LOOP
               JMP CHAR_AGN



 FLUSH_BUF : MOV CX,MAX_STR_LENGTH
     ERASE : CALL BACK_SPACE
             LOOP ERASE
             JMP CHAR_AGN


  ENTER_KEY : MOV CUR_X,1H
              MOV CURLEFT,0H
              INC CUR_Y
              CALL EOF_CURLINE_CUR_Y
              MOV IF_ERR_1,0

              CALC_SI
              MOV BX,0H
              JMP CHAR_AGN

              RET
READ_STRING   ENDP


BACK_SPACE PROC NEAR
          PUSH AX
          PUSH DX
          
          CMP BX,0H
          JE END_BS
          DEC BX
          
          DEC CUR_X
          MOV DL,' '
          CALL PUT_CHAR
          DEC CUR_X
          
          SET_CURSOR
  END_BS: POP DX
          POP AX
          RET
BACK_SPACE ENDP

;--------------------------------------------------------------------
; * read key input
; - AL : ASCII code
; - AH : SCAN code
;--------------------------------------------------------------------
READ_KEY PROC
   MOV AH,0H
   INT 16H
   RET
READ_KEY ENDP


;--------------------------------------------------------------
; * save file
; FILENAME : the name of file where TEXT will be saved.
; EOF : end of line num of file
;--------------------------------------------------------------
SAVE_FILE PROC NEAR
          PUSH AX
          PUSH BX
          PUSH CX
          PUSH DX
          PUSH SI

          MOV AH,CUR_Y   ; save CUR_Y and CURLINE
          MOV AL,CURLINE
          PUSH AX
          MOV AH,CUR_X
          PUSH AX

          MOV AH,3CH ; create a file
          MOV CX,0H
          LEA DX,FILENAME
          INT 21H
          JC SAVE_ERR
          
          MOV BX,AX ; save file handle

          LEA DX,TEXT
          MOV CURLINE,22D ; save from the beginning of TABLE
          MOV CUR_Y,2D

SAVE_NEXT:GET_LINE_END
          XOR AH,AH
          MOV CX,AX ; give bytes of first line
          JCXZ NO_LINE ; there is no character in the line

          MOV AH,40H
          INT 21H
          JC SAVE_ERR

NO_LINE:  PUSH DX
          MOV AH,40H
          MOV CX,2H
          LEA DX,CR_LF ; save CR,LF
          INT 21H
          POP DX
          JC SAVE_ERR

          ADD DX,MAX_STR_LENGTH
          INC CUR_Y
          MOV AL,EOF
          SUB AL,CURLINE
          ADD AL,22D
          ADD AL,2D
          CMP AL,CUR_Y ; is EOF > (CUR_Y-2)+(CURLEFT-22)
          JAE SAVE_NEXT ; below then, finish.

          BLACK_LINE
          MOV CUR_X,3 ; saved message
          MOV CUR_Y,24
          MOV ATTR,70H
          MOV SI,OFFSET SAVED_MSG
          CALL PUT_STRING
          CALL READ_KEY
          FILE_TO_BACK
          MOV AH,3EH
          INT 21H ; close file
          JMP END_SAVE

SAVE_ERR : FP_ERR

END_SAVE: POP AX
          MOV CUR_X,AH
          POP AX
          MOV CUR_Y,AH
          MOV CURLINE,AL
          POP SI
          POP DX
          POP CX
          POP BX
          POP AX
          RET
SAVE_FILE ENDP

;----------------------------------------------------------------
; * GET FILENAME
; * used during SAVE AS.
;   CALL GIVE_FILE first, CALL SAVE_FILE to do SAVE AS...
; * used when LOAD
;   CALL GIVE_FILE first, CALL LOAD_FILE to do LOAD
;
; FILENAME : filename
;            maximum legnth is XXXXXXXX.XXX
;            followed by 0(to open/save),$(to print in screen)
; TEMP : used to input string
;        content will be copied to FILENAME
;----------------------------------------------------------------
GIVE_FILE PROC
          PUSH AX
          PUSH BX
          PUSH CX
          PUSH DX
          PUSH SI
          PUSH DI
          PUSH ES
          MOV AH,CUR_X
          MOV AL,CUR_Y
          PUSH AX

          BLACK_LINE
          MOV CUR_X,3  ; print message
          MOV CUR_Y,24
          LEA SI,FILE_MSG
          CALL PUT_STRING
          
          ADD CUR_X,12 ; get input
          SET_CURSOR
          LEA DX,TEMP
          MOV AH,0AH
          INT 21H

          INC DX
          INC DX
          
          MOV AX,DATA ; copy TEMP to FILENAME
          MOV ES,AX
          MOV CX,12D
          MOV SI,DX
          LEA DI,FILENAME
 COPY:    LODSB
          CMP AL,CR
          JE END_COPY
          STOSB
          LOOP COPY

 END_COPY:MOV AL,0 ; followed by 0,$
          STOSB
          MOV AL,'$'
          STOSB

          LEA BX,TEMP   ; clear buffer
          MOV BYTE PTR[BX],13D
          LEA DI,TEMP
          INC DI
          MOV CX,32D
          MOV AL,00
          REP STOSB
          
          POP AX
          MOV CUR_X,AH
          MOV CUR_Y,AL
          POP ES
          POP DI
          POP SI
          POP DX
          POP CX
          POP BX
          POP AX
          RET
GIVE_FILE ENDP

;-----------------------------------------------------------------
; * load file
; FILENAME : filename to read in
;-----------------------------------------------------------------
LOAD_FILE PROC NEAR
          PUSH AX
          PUSH CX
          PUSH DX
          PUSH DI
          PUSH ES
          PUSH SI    
          PUSH BX

          CLD
          MOV AX,DATA
          MOV ES,AX
          MOV DI,OFFSET LINE_END
          MOV AL,0
          MOV CX,MAX_LINE
          REP STOSB
          MOV DI,OFFSET TEXT
          MOV AL,' '
          MOV CX,32D*1024D
          REP STOSB

          
          MOV AH,3DH  ; open file
          LEA DX,FILENAME
          MOV AL,0
          INT 21H
          JC LOAD_ERR
          MOV BX,AX ; save handle
          
          LEA DX,TEXT 
          
          MOV COUNT_X,0
          MOV COUNT_Y,0
          
NEXT_IN:  MOV AH,3FH
          MOV CX,1H
          INT 21H ; read character
          JC LOAD_ERR
          OR AX,AX
          JZ READ_END

          MOV SI,DX
          CMP BYTE PTR[SI],CR
          JE NEXT_LINE
          INC COUNT_X
          INC DX
          JMP NEXT_IN

NEXT_LINE : MOV AH,3FH
            MOV CX,1H
            INT 21H
            JC LOAD_ERR
            MOV SI,DX
            MOV BYTE PTR[SI],' ' ; discard LF
            
            PUSH AX  ; save LINE_END information
            PUSH BX  
            MOV BX,OFFSET LINE_END
            MOV AL,COUNT_Y
            XOR AH,AH
            ADD BX,AX
            MOV AL,COUNT_X
            MOV [BX],AL
            MOV AL,COUNT_X
            SUB DX,AX
            ADD DX,MAX_STR_LENGTH
            MOV COUNT_X,0
            INC COUNT_Y
            POP BX
            POP AX
            
            JMP NEXT_IN

 
READ_END :  MOV DI,DX  ; delete LF
            MOV AL,' '
            STOSB 
            
            MOV BX,OFFSET LINE_END ; save end line's LINE_END
            MOV AL,COUNT_Y
            XOR AH,AH
            ADD BX,AX
            MOV AL,COUNT_Y
            DEC AL
            MOV [BX],AL
           
           INC AL
           MOV EOF,AL

           
           MOV AH,CUR_X
           MOV AL,CUR_Y
           PUSH AX
           BLACK_LINE
           MOV CUR_X,3 ; loaded message
           MOV CUR_Y,24
           MOV ATTR,70H
           MOV SI,OFFSET LOADED_MSG
           CALL PUT_STRING
           CALL READ_KEY
           POP AX
           MOV CUR_X,AH
           MOV CUR_Y,AL
           
           FILE_TO_BACK
           JMP LOAD_END
LOAD_ERR : FP_ERR
           
           POP BX
           POP SI
           POP ES
           POP DI
           POP DX
           POP CX
           POP AX
           RET


LOAD_END : MOV AH,3EH
           INT 21H ; close file
           
           POP BX
           POP SI
           POP ES
           POP DI
           POP DX
           POP CX
           POP AX
           MOV SI,OFFSET TEXT ; initialize variables
           MOV BX,0
           MOV CUR_X,1
           MOV CUR_Y,2
           MOV CURLINE,22
           MOV CURLEFT,0
           CALL PAINT_SCR
           RET
LOAD_FILE ENDP

;----------------------------------------------------------------
; * NEW
; * ask new message
; * when new, clear TEXT,LINE_END
;----------------------------------------------------------------
NEW_TEXT PROC NEAR
         PUSH AX
         PUSH CX
         PUSH ES
         PUSH SI
         PUSH DI
         MOV AH,CUR_X
         MOV AL,CUR_Y
         PUSH AX

         BLACK_LINE
         MOV CUR_X,3
         MOV CUR_Y,24
         MOV ATTR,70H
         MOV SI,OFFSET NEW_MSG ; ask : new?
         CALL PUT_STRING
         POP AX
         MOV CUR_X,AH
         MOV CUR_Y,AL
         CALL READ_KEY
         CMP AL,'Y'
         JE DELETE
         CMP AL,'y'
         JE DELETE
         POP DI
         POP SI
         POP ES
         POP CX
         POP AX
         RET

DELETE : MOV AX,DATA
         MOV ES,AX
         
         MOV DI,OFFSET TEXT ; clear TEXT
         MOV CX,32D*1024D
         MOV AL,' '
         REP STOSB
         
         MOV DI,OFFSET LINE_END ; clear LINE_END
         MOV AL,0
         MOV CX,MAX_LINE
         REP STOSB
         MOV CUR_X,1
         MOV CUR_Y,2
         MOV CURLINE,22
         MOV CURLEFT,0
         MOV EOF,0
         CALL PAINT_SCR
         
         LEA DI,FILENAME  ; give FILENAME as NONAME00.TXT
         LEA SI,NEW_NAME
         MOV CX,14D
         REP MOVSB

         POP DI
         POP SI
         POP ES
         POP CX
         POP AX
         MOV BX,0
         MOV SI,OFFSET TEXT
         RET
NEW_TEXT ENDP


;-----------------------------------------------------------------
; * Exit
; * ask exit message before exit
;-----------------------------------------------------------------
EXIT PROC NEAR
         PUSH AX
         PUSH SI
         MOV AH,CUR_X
         MOV AL,CUR_Y
         PUSH AX

         BLACK_LINE
         MOV CUR_X,3
         MOV CUR_Y,24
         MOV ATTR,70H
         MOV SI,OFFSET EXIT_MSG ; ask : exit?
         CALL PUT_STRING
         POP AX
         MOV CUR_X,AH
         MOV CUR_Y,AL
         CALL READ_KEY
         CMP AL,'Y'
         JE EXIT_PG
         CMP AL,'y'
         JE EXIT_PG
         
         POP SI  ; Do not exit. return;
         POP AX
         RET

EXIT_PG: MOV CUR_X,0
         MOV CUR_Y,0
         MOV DL,' '
         MOV ATTR,07H

L_ERASE: CALL PUT_CHAR ; erase screen before exit
         CMP CUR_X,80D
         JB L_ERASE
         INC CUR_Y
         MOV CUR_X,0
         CMP CUR_Y,25D
         JB L_ERASE
         MOV CUR_X,0
         MOV CUR_Y,0
         SET_CURSOR
         MOV AX,4C00H
         INT 21H
EXIT ENDP

CODE ENDS
 END PROGSTART
