home *** CD-ROM | disk | FTP | other *** search
/ Frostbyte's 1980s DOS Shareware Collection / floppyshareware.zip / floppyshareware / USCX / ASMUT-03.ZIP / DOS-EDIT.ASM < prev    next >
Assembly Source File  |  1984-05-03  |  62KB  |  1,136 lines

  1.         PAGE    60,132
  2. ;***************************************************************************
  3. ; General comments
  4. ;***************************************************************************
  5. ; The following comprises the disassembled and documented version of DOS-ED
  6. ; as it exists on Compuserve's XA6 data base.  If one reassembles this
  7. ; program one will obtain the exact version of DOS-ED.COM that exists on
  8. ; that database.  No attempt has been made to make improvements to this code
  9. ; other than to indicate in the margin were some could (and probably should)
  10. ; be made.  If you notice that the program sizes are different between this
  11. ; reassembled and relinked version and the version that has been generated
  12. ; from the HEX file on CIS, that is because there is some trailing garbage
  13. ; on the CIS file.  You can strip it off in the debugger and the files will
  14. ; compare exactly.
  15. ;
  16. ; Even after disassembling and documenting this code I have a few questions
  17. ; about what was being done in places.  If my comments seem spurious at
  18. ; times, then just take them with a grain of salt.  They should help you
  19. ; understand this code for the most part.
  20. ;
  21. ; When linking this program you should expect to receive a No Stack warning
  22. ; message along with an Unsatisfied external error on DOS_RETURN.  These
  23. ; are normal and should be ignored.
  24. ;
  25. ; DOS-ED is a fine piece of programming performed by Jack Gersbach.
  26. ; This disassembly and documentation was done by myself.
  27. ;                                     - Scott W. Killen
  28. ;
  29. ;***************************************************************************
  30. ; Definitions and commentary on conventions in coding
  31. ;***************************************************************************
  32. ; Register usage:  (Most common (but not exclusive) uses are listed)
  33. ; AX, DX, CX - Used for many reasons
  34. ; DH - Usually current row on crt
  35. ; DL - Usually current col on crt
  36. ; SI - Usually points to offset of current character in input buffer (first character is offset 0)
  37. ; DI - Usually has the value of one of the following:
  38. ;      * The number of characters currently in the input buffer   *or*
  39. ;      * Points to a destination in the text holding buffer
  40. ; BX - Usually contains the address at which the first character in the input buffer is located.
  41. ;         (The two characters before this are the max buffer size and length of string
  42. ;          characters.)
  43. ; BP - Usually a register of flags organized as bits |01234567| where:
  44. ;      Bits 0-3 have no function
  45. ;      Bit 4 - Off means the input buffer has been altered since interrupt processing began.
  46. ;              On means *only* lateral cursor positioning commands have been issued since interrupt
  47. ;                 processing began.
  48. ;      Bit 5 - Off means previous line from holding buffer, On means original line
  49. ;      Bit 6 - Off means no changes to current line in input buffer, On means changes have been made
  50. ;      Bit 7 - Applies to the redisplay of lines on the screen after an intra-line edit operation
  51. ;                 Off means line wasn't shortened therefore no trailing blanks needed
  52. ;                 On means line is now shorter and blanks are needed over trailing characters
  53. ;
  54. ; Memory Usage:
  55. ; ES:[0450H] - Contains current cursor position in Bios data area
  56. ; ES:[044AH] - Contains # of columns of current crt screen in Bios data area
  57. ; ES:[0417H] - Keyboard flag, containing insert, shift, num lock, scroll lock etc in Bios data area
  58. ;                   insert flag bit is 80h
  59. ;
  60. ; CS:[inline_mod1+1] - Jump return address to normal DOS funcion processing
  61. ; CS:[inline_mod2+1] - Current cursor definition (start/stop lines)
  62. ; CS:[inline_mod3+1] - Screen location of end of line (row/col)
  63. ; CS:[inline_mod4+2] - Higher of DS or CS on entry into interrupt.
  64. ; CS:[inline_mod5+2] - Maximum size of input buffer
  65. ;
  66. ; start_off  - Offset of start of input buffer on screen (example if prompt is A> then screen column position
  67. ;                   of input buffer start would be 2
  68. ; current_col - Current column position on screen (1st column is 0)
  69. ; last_entry - Address (offset) of last string accessed in text buffer
  70. ; next_entry - Address (offset) of next available block in text buffer
  71. ; buffer_bot - Base address of text buffer
  72. ; buffer_top - Top address of text buffer
  73. ; aux_last  \
  74. ; aux_next   \ Same as previous four except for auxiliary buffer
  75. ; aux_bot    /
  76. ; aux_top   /
  77. ;
  78.  
  79. ; Character equates
  80. ACK              equ  06h  ; Acknowledge character (Cntrl F)
  81. BELL             equ  07h  ; Bell character        (Cntrl G)
  82. BACKSPACE        equ  08h  ; Backspace character
  83. TAB              equ  09h  ; Tab character
  84. ESC              equ  1Bh  ; Escape character
  85. BLANK            equ  20h  ; Space character
  86. CR               equ  0dh  ; carriage return
  87. LF               equ  0ah  ; Line feed
  88. HAT              equ  5eh  ; "^" character
  89. SMALLA           equ  61h  ; "a" character
  90. LEFT_CURLY_BRACE equ  7Bh  ; "{" character
  91. CNTL_BACKSPACE   equ  7fh  ; Control and backspace pressed simultaneously
  92.  
  93. ; Masks
  94. INSERT_ON_MASK   equ  80h  ; Insert key bit on, corresponding to keyboard status word
  95. INSERT_OFF_MASK  equ  7fh  ; Insert key bit off, corresponding to keyboard status word
  96. LENGTH_BYTE_MASK equ  80h  ; Mask to identify the text string length bit in text buffer
  97. LENGTH_OFF_MASK  equ  7fh  ; Mask to turn of the length byte identifier
  98. UPPER_CASE_MASK  equ  40h  ; Convert control character to upper case character
  99. LOWER_CASE_MASK  equ  20h  ; Convert upper case character to lower case character
  100.  
  101. ; Physical characteristics
  102. ROWS_ON_CRT       equ 19h               ; Ordinal number of lines on crt
  103. LAST_ROW_ON_CRT   equ  ROWS_ON_CRT - 1  ; Offset of last line on crt (top line is line 0)
  104. MONO_CUR_DEF      equ  0B0Ch            ; Start, stop lines of cursor
  105. MONO_CUR_STOP     equ  0Ch              ; Stop line for standard cursor
  106. GRAPHICS_CUR_DEF  equ  0607h            ; Start, stop lines of cursor for graphics device
  107. GRAPHICS_CUR_STOP equ  07h              ; Stop line for standard cursor for graphics device
  108. TEXT_BUFFER_START equ 60h               ; Start address for text holding buffer
  109. TEXT_BUFFER_END   equ 160h              ; End address for text holding buffer
  110. TEXT_BUFFER_SIZE  equ TEXT_BUFFER_END - TEXT_BUFFER_START ; Extent of text buffer
  111. BOTH_BUFFS_SIZE   equ TEXT_BUFFER_SIZE + TEXT_BUFFER_SIZE ; Combined buffer size
  112. AUX_BUFFER_START  equ 160h              ; Auxiliary holding buffer start address
  113. AUX_BUFFER_END    equ 260h              ; Auxilliary holding buffer end address
  114.                                         ; *NOTE* TEXT_BUFFER_END - TEXT_BUFFER_START =
  115.                                         ;        AUX_BUFFER_END - AUX_BUFFER_START
  116.  
  117. ; Bios interrupt 10 functions
  118. SET_CURSOR_TYPE  equ  01h
  119. SET_CURSOR_POSN  equ  02h
  120. READ_CURSOR_POSN equ  03h
  121. READ_VIDEO_STATE equ  0fh
  122.  
  123. ; Dos interrupt 21 functions
  124. INPUT_CHR_NOECHO  equ  08h
  125. OUTPUT_CHR        equ  02h
  126.  
  127. ;***************************************************************************
  128. ; BIOS data segment definition
  129. ;***************************************************************************
  130. BIOSEG  SEGMENT at 0h
  131.         org 417h
  132.         kbd_flag     db  ?
  133.         org 44ah
  134.         crt_cols     dw  ?
  135.         org 450h
  136.         cursor_posn  dw  ?
  137. BIOSEG  ends
  138.  
  139. ;***************************************************************************
  140. ; DOS-ED code segment begins
  141. ;***************************************************************************
  142. CSEG    SEGMENT
  143.         ASSUME CS:CSEG
  144.         ORG 100H
  145. DOSED   PROC NEAR
  146.  
  147.         MOV     SI,offset loadlabel    ; Source of code to move is at loadlable
  148.         MOV     DI,offset initialize   ; Destination is at end of file at initialize
  149.         MOV     CX,offset line_table   ; Above the code to be moved is linetable
  150.         SUB     CX,SI                  ; The difference is the amount of code to be moved
  151.         repz MOVSB                     ; Move it!!
  152.         JMP     initialize             ; Now go do it.
  153.  
  154. loadlabel:
  155.         XOR     AX,AX                       ; Clear AX
  156.         MOV     DS,AX                       ; Prepare to save original interrupt
  157.         MOV     SI,0084H                    ; Source for INT 21h as provided for in the interrupt table
  158.         MOV     DI, offset [inline_mod1+1]  ; Destination in the code segment for moving this pointer
  159.         MOVSW                               ; Move the two word address
  160.         MOVSW
  161.         MOV     AX, offset entry_point ; Move this programs starting address into the dos interrupt slot
  162.         MOV     [SI-04H],AX            ; Move offset in line
  163.         MOV     [SI-02H],CS            ; Move segment value in line
  164.         MOV     DI, TEXT_BUFFER_START  ; Working buffer begins at offset 60h which is Formatted parameter
  165.         MOV     CX, BOTH_BUFFS_SIZE    ;   area 1 in the Program Segment Prefix.
  166.         MOV     AL, CR                 ; Fill 512 bytes with CR characters.  Note that this technique uses
  167.         repz STOSB                     ;   161 bytes of PSP for storage!  Very Clever!
  168.         MOV     DX, offset initialize  ; Dos may load above this address
  169.         INT     27H                    ; Terminate but stay resident
  170.  
  171. line_table      db  300 dup (?)
  172.  
  173. entry_point:
  174.         CMP     AH,0AH               ; Is this function 10?
  175.         JE      wrapper              ; Nope, continue with normal Dos 21 interrupt
  176.         EXTRN   DOS_RETURN:FAR
  177.  
  178. inline_mod1:
  179.         JMP     DOS_RETURN           ; This code is modified in line!
  180.                                      ;    Go to normal Dos function handling.
  181.  
  182. wrapper:
  183.         PUSH    AX
  184.         PUSH    BX
  185.         PUSH    CX
  186.         PUSH    DX
  187.         PUSH    SI
  188.         PUSH    DI
  189.         PUSH    BP
  190.         PUSH    DS
  191.         PUSH    ES
  192.         STI
  193.         CALL    begin_dosed
  194.         POP     ES
  195.         POP     DS
  196.         POP     BP
  197.         POP     DI
  198.         POP     SI
  199.         POP     DX
  200.         POP     CX
  201.         POP     BX
  202.         POP     AX
  203.         MOV     AL,00H
  204.         IRET
  205.  
  206. ;***************************************************************************
  207. ; Extended keystroke recognition and branching tables
  208. ;***************************************************************************
  209.                 ; Table 1 of extended keyboard function codes
  210. table1:
  211. t1_1    db  0fh ; Back Tab
  212. t1_2    db  47h ; Home key
  213. t1_3    db  48h ; Up arrow
  214. t1_4    db  4bh ; Left arrow
  215. t1_5    db  4dh ; Right arrow
  216. t1_6    db  4fh ; End key
  217. t1_7    db  50h ; Down Arrow
  218. t1_8    db  53h ; Del key
  219. t1_9    db  73h ; Cntrl Left Arrow
  220. t1_a    db  74h ; Cntrl Right Arrow
  221. t1_b    db  75h ; Cntrl End
  222. t1_c    db  77h ; Cntrl Home
  223. t1_d    db  76h ; Cntrl PgDn
  224. t1_e    db  84h ; Cntrl PgUp
  225. t1_f    db  00h ; ?
  226.                     ; Table 2 indexes correspond to table 1 indexes
  227.                     ; and points to code address where the function is handled.
  228. table2:
  229. t2_f    dw offset error_return        ;    0ah, 05h   ; ?
  230. t2_e    dw offset cntrl_page_up       ;    74h, 07h   ; Cntrl PgUp
  231. t2_d    dw offset cntrl_page_down     ;   0a9h, 06h   ; Cntrl PgDn
  232. t2_c    dw offset cntrl_home          ;    0bh, 05h   ; Cntrl Home
  233. t2_b    dw offset cntrl_end           ;    27h, 05h   ; Cntrl End
  234. t2_a    dw offset cntrl_right_arrow   ;    41h, 05h   ; Cntrl Right Arrow
  235. t2_9    dw offset cntrl_left_arrow    ;    83h, 05h   ; Cntrl Left Arrow
  236. t2_8    dw offset del_key             ;   0edh, 05h   ; Del key
  237. t2_7    dw offset down_arrow          ;    44h, 06h   ; Down Arrow
  238. t2_6    dw offset end_key             ;   0e4h, 04h   ; End key
  239. t2_5    dw offset right_arrow         ;    67h, 05h   ; Right arrow
  240. t2_4    dw offset left_arrow          ;    99h, 05h   ; Left arrow
  241. t2_3    dw offset up_arrow            ;    43h, 06h   ; Up arrow
  242. t2_2    dw offset home_key            ;   0e1h, 05h   ; Home
  243. t2_1    dw offset backtab             ;    8dh, 05h   ; Backtab
  244.  
  245. ;***************************************************************************
  246. ; Display and output services
  247. ;***************************************************************************
  248. screen_and_display:                 ; Screen out control characters of form ^x
  249.         CMP     AL, BLANK           ; Compare AL to blank character
  250.         JNB     display_one_char    ; If we have a printable character go to display routine
  251.         CMP     AL, TAB             ; Is this a forward tab?
  252.         JE      display_one_char    ; If so, go display.
  253.         PUSH    AX                  ; No, this is a "normal" control character
  254.         MOV     AL,HAT              ; Place a "^" character in AL
  255.         CALL    display_one_char    ; Print the "^" out.
  256.         POP     AX                  ; Now convert the Control character to its
  257.         OR      AL, UPPER_CASE_MASK ; upper case equivalent and print it.  Result is "^E"
  258.                                     ;    construct for representing control characters.
  259.  
  260. display_one_char:
  261.         CMP     AL, BLANK           ; Does AL contain a blank character
  262.         JB      display_cntrl_chr   ; Jump if we have a control character
  263.  
  264. ready_display:
  265.         CMP     AL, CNTL_BACKSPACE           ; Don't increment column counter if this
  266.         JE      output_to_display            ;    is a control Backspace character
  267.         INC     BYTE PTR CS:[current_col]    ; Increment column position because we received
  268.                                              ;    something printable
  269. output_to_display:
  270.         PUSH    DX                           ; Save the DX register and set up the
  271.         XCHG    AX,DX                        ;    AH register for a DOS function 2 (Display
  272.         MOV     AH,  OUTPUT_CHR              ;    output) call.
  273.         INT     21H
  274.         XCHG    AX,DX                        ; Restore the AX register
  275.         POP     DX                           ;    and restore the DX register
  276.         RET
  277.  
  278. display_cntrl_chr:                           ; Process a control character for output
  279.         CMP     AL, CR                       ; Is this a carriage return character?
  280.         JE      cr_out                       ; If so go take care of it
  281.         CMP     AL, BACKSPACE                ; Is this a backspace?
  282.         JE      bs_out                       ; If so we need to take care of it
  283.         CMP     AL, TAB                      ; Maybe its a tab character
  284.         JNE     relay_to_output              ; Continue if its not a tab
  285.         MOV     AL,BYTE PTR CS:[current_col] ; Set AL to current column on screen
  286.         OR      AL,0F8H                      ; Get the number of spaces to the next
  287.         NEG     AL                           ;    8 byte boundary
  288.         PUSH    CX                           ; Save the CX register
  289.         MOV     CL,AL                        ; Place the count of blanks to be output in CL
  290.         mov     ch, 00h                      ; Zero out high byte
  291.         JCXZ    skip_tabbing                 ; Dont do anything if count is zero
  292.  
  293. tab_loop:
  294.         MOV     AL, BLANK                    ; Ok, now print out all necessary
  295.         CALL    display_one_char             ;    blanks to reach an 8 character
  296.         LOOP    tab_loop                     ;    boundary.
  297.  
  298. skip_tabbing:
  299.         POP     CX                           ; Restore the CX register.
  300.         RET
  301.  
  302. cr_out:
  303.         MOV     CS:BYTE PTR [current_col],00H   ; Reset current column pointer to zero
  304.  
  305. relay_to_output:
  306.         JMP     SHORT output_to_display
  307.  
  308. bs_out:
  309.         DEC     BYTE PTR CS:[current_col]  ; Decrement the current column pointer
  310.         PUSH    AX                         ; Save the character in register AX
  311.         PUSH    DX                         ; Save the DX register
  312.         MOV     DX,ES:[0050H]              ; Get the Cursor position from Bios data area
  313.         MOV     AH,ES:[004AH]              ; Get the # of CRT cols on screen from Bios data area
  314.         OR      DL,DL                      ; Are we at column zero?
  315.         JNE     bs_end                     ; If not forget the rest.
  316.         OR      DH,DH                      ; Are off the screen at the top?
  317.         JNE     set_cur_loc                ; If not then dont reset rows
  318.         MOV     DH, ROWS_ON_CRT            ; (Re)set row value to 25
  319.  
  320. set_cur_loc:
  321.         DEC     DH                         ; Decrement the row count
  322.         MOV     DL,AH                      ; Move in # of columns.  (0, 0) is home.
  323.         PUSH    BX                         ; Save BX
  324.         MOV     BH,00H                     ; Prepare for BIOS interrupt 10 funtion 2
  325.         MOV     AH, SET_CURSOR_POSN        ;    call (Set cursor position)
  326.         INT     10H                        ; Do it.
  327.         POP     BX                         ; Restore BX
  328.  
  329. bs_end:
  330.         POP     DX                         ; Restore DX register
  331.         POP     AX                         ; and the AX register
  332.         JMP     SHORT relay_to_output      ; and now we are done.
  333.  
  334. decrement_col_row:                         ; Wrap back if line spans two screen lines
  335.         OR      DL,DL                      ; Are we at column zero
  336.         JNE     dcr_end                    ; If so then dont worry about row update
  337.         DEC     DH                         ; Yep, decrement the row pointer
  338.         MOV     DL,BYTE PTR ES:[crt_cols]  ; Get the # of CRT cols per screen from Bios data area
  339.  
  340. dcr_end:
  341.         DEC     DL                         ; Decrement the column pointer
  342.         RET
  343.  
  344. display_blank:
  345.         MOV     AL, BLANK
  346.  
  347. display_and_test:                             ; Display and test for updated cursor location
  348.         PUSH    CX                            ; Save CX register
  349.         MOV     CX,ES:[cursor_posn]           ; Load CX with cursor position from Bios
  350.         CALL    screen_and_display            ; Send the character in AL to output display
  351.         CMP     CH, LAST_ROW_ON_CRT           ; Are we on the last row?
  352.         JNE     dat_end                       ; If not then no further tests are needed
  353.         CMP     CL,BYTE PTR ES:[cursor_posn]  ; Are we now on a new column?  (alternative question
  354.                                               ;    is: have we scrolled?)
  355.         JBE     dat_end                       ; If current location > cl then yes we have scrolled
  356.                                               ;    up a line and need to decrement the line pointer
  357.         DEC     DH                            ; Decrement the line pointer
  358.  
  359. dat_end:
  360.         POP     CX                   ; Restore CX
  361.         RET
  362. ;***************************************************************************
  363.  
  364. set_cursor:
  365.         PUSH    BX
  366.         PUSH    CX
  367.         PUSH    DX
  368.         PUSH    BP                                  ; Save registers
  369.         PUSH    SI
  370.         PUSH    DI
  371.  
  372. inline_mod2:
  373.         MOV     CX, MONO_CUR_DEF                       ; Assume Standard char def
  374.                                                        ;   (Note that this word is modified
  375.                                                        ;    in line if it is later determined
  376.                                                        ;    that a graphics board is in use)
  377.         TEST    BYTE PTR ES:[kbd_flag], INSERT_ON_MASK ; Is insert on?
  378.         JE      after_box                              ; If not then branch
  379.         MOV     CH,CL                                  ; Yep, turn the cursor into
  380.         SHR     CH,1                                   ;   a half sized box
  381.  
  382. after_box:
  383.         MOV     AH, SET_CURSOR_TYPE                    ; Set up and call Bios for
  384.         INT     10H                                    ;   support.
  385.         POP     DI
  386.         POP     SI
  387.         POP     BP                                     ; Restore Registers
  388.         POP     DX
  389.         POP     CX
  390.         POP     BX
  391.         MOV     AX,WORD PTR ES:[cursor_posn]            ; Load AX with current cursor position
  392.  
  393. inline_mod3:
  394.         CMP     AX,0888H                                 ; Compare current cursor position to end of line position
  395.         JB      sc_ret                                   ; If less than then dont update end of line position
  396.         MOV     CS:WORD PTR [inline_mod3+1],AX  ; Modify end of line address with value of current cursor position
  397.  
  398. sc_ret:
  399.         RET
  400.  
  401. credit  db 'DOS EDITOR BY J. Gersbach',CR,LF,00
  402.  
  403.  
  404. begin_dosed:                            ; Save registers
  405.         PUSH    BX
  406.         PUSH    CX
  407.         PUSH    DX
  408.         MOV     BH,00H                  ; Set up to read current cursor position
  409.         MOV     AH, READ_CURSOR_POSN    ; Cursor position returned as DH, DL is row, col
  410.         INT     10H                     ; Read the current cursor position into DH, DL
  411.         MOV     CS:[start_off],DL       ; Move current column into storage
  412.         MOV     CS:[current_col],DL     ; Move current column into storage
  413.         CMP     CL, MONO_CUR_STOP       ; Check: Is current end line for cursor = 12
  414.         JB      bd2                     ; Branch if less than 12
  415.         MOV     AH, READ_VIDEO_STATE    ; Set up to return current video state
  416.         INT     10H                     ; Go get it
  417.         CMP     AL, GRAPHICS_CUR_STOP   ; Is this a 80x25 BW card
  418.         MOV     CX, MONO_CUR_DEF        ; Set start/stop lines for cursor to 11/12
  419.         JE      bd1                     ; Yes it is 80x25 BW card, branch
  420.         MOV     CX, GRAPHICS_CUR_DEF    ; No its not 80x25 card, start/stop lines are 6/7
  421.  
  422. bd1:
  423.         MOV     AH, SET_CURSOR_TYPE     ; Set function call to set cursor type
  424.         INT     10H                     ; Do it
  425.  
  426. bd2:
  427.         MOV     CS:WORD PTR [inline_mod2+1],CX   ; Save the cursor type setting in line
  428.         POP     DX
  429.         POP     CX
  430.         POP     BX
  431.         MOV     BX,DX                           ; DX points to offset of input buffer
  432.         MOV     AL,[BX]                         ; Get the number of characters in the buffer
  433.         CMP     AL,02H                          ; Is it bigger than 2 characters?
  434.         JB      sc_ret                          ; Nope, we have a problem here!
  435.         DEC     AL                              ; Now decrement AL to get number of real characters
  436.         MOV     AH, 00H                         ;    buffer han hold.   Zero out AH
  437.         MOV     CS:WORD PTR [inline_mod5+2],AX  ; AX now contains the max number of chars that the buffer
  438.                                                 ;    can hold.
  439.         ADD     BX,02H                          ; BX points to address at which to put first real character
  440.                                                 ;    in input buffer
  441. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  442.                                                 ;;  AUTOMATIC BUFFER TOGGLE (Why, I don't know)
  443. auto_buffer_toggle:                             ;;
  444.         MOV     BP,DS                           ;;  Place the DS register into BP
  445.         PUSH    DS                              ;;  Save the value of the DS register
  446.         MOV     DI,CS                           ;;  Place the CS register into DI
  447.         MOV     DS,DI                           ;;     and also into DS
  448.         CMP     BP,DI                           ;;  Compare DS : CS values
  449.         JB      abt1                            ;;  If DS < CS then jump
  450.                                                 ;;
  451. inline_mod4:                                    ;;
  452.         CMP     DI,0888H                        ;;  Compare CS : AUX    (this in-line address will be called AUXiliary)
  453.         JE      abt2                            ;;  If its equal (if we came this way last time!) then go swap
  454.         JMP     SHORT after_swap_loop           ;;  If so then avoid swaps
  455.                                                 ;;
  456. abt1:                                           ;;
  457.         MOV     BP,DI                           ;;  Set BP to highest register value (now determined to be CS)
  458.         CMP     DI,DS:WORD PTR [inline_mod4+2]  ;;  Compare CS : AUX
  459.         JE      after_swap_loop                 ;;  If its not equal (if we came this way last time!) then go swap
  460.                                                 ;;
  461. abt2:                                           ;;
  462.         PUSH    CS                              ;;  Now we must swap the appropriate memory locations to allow the
  463.         POP     ES                              ;;     editor to use the other buffer (There are two buffers that one
  464.                                                 ;;     can transfer between depending on DS : CS relationship.
  465.         MOV     SI,offset last_entry            ;;  Load SI with starting address
  466.         LEA     DI,[SI+08H]                     ;;  Load DI with second starting address
  467.         MOV     CX,0004H                        ;;  4 words are to be moved ... in order ... address of last string accessed,
  468.                                                 ;;     address of highest available byte, base address of text holding buffer,
  469.                                                 ;;     high address of holding buffer.
  470.                                                 ;;  Values are initiallized to:
  471.                                                 ;;     1st buffer - 60h, 60h, 60h, 160h
  472.                                                 ;;     2nd buffer - 160h, 160h, 160h, 260h
  473.                                                 ;;
  474. swap_loop:                                      ;;
  475.         MOV     AX,[DI]                         ;;  Save the value in the secondary buffer
  476.         MOVSW                                   ;;  Move the primary buffer value into the secondary buffer position
  477.         MOV     [SI-02H],AX                     ;;  Replace emptied location with saved value
  478.         LOOP    swap_loop                       ;;  Go back and swap next set of values
  479.                                                 ;;
  480. after_swap_loop:                                ;;
  481.         MOV     DS:WORD PTR [inline_mod4+2],BP  ;;  Load AUX such that AUX = Max(CS, DS)
  482.         POP     DS                              ;;  Restore DS
  483. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  484.         MOV     BP,000CH
  485.         JMP     SHORT rib1
  486.  
  487. reinit_buffer:
  488.         MOV     BP,0004H
  489.  
  490. rib1:
  491.         XOR     SI,SI                                    ; Zero out Source index
  492.         MOV     CS:WORD PTR [inline_mod3+1],SI           ; Modify inline address just above
  493.         XOR     DI,DI                                    ; Zero out Destination index
  494.         MOV     ES,DI                                    ; Zero out the ES register
  495.         AND     BYTE PTR ES:[kbd_flag], INSERT_OFF_MASK  ; Turn insert off
  496.  
  497. start_read_char:
  498.         AND     BP,0FFFEH                  ; Turn off low bit in BP (Line may be shorter)
  499.         CALL    set_cursor                 ; Set the cursor shape as per mode
  500.         XCHG    AX,DX                      ; Save AX in DX
  501.         MOV     AH, INPUT_CHR_NOECHO       ; Get a character from the keyboard
  502.         INT     21H                        ; Call DOS for service
  503.         CMP     AL, ACK                    ; Is it an acknowledge character?
  504.         JE      start_read_char            ; If so ... just forget it and go back
  505.         MOV     CX, offset start_read_char ; Save address of start_read_char label
  506.         PUSH    CX                         ; This is a return address for a nonexistent call!
  507.         OR      AL,AL                      ; Set up for test
  508.         JNE     normal_keyboard_chr        ; Jump if non null character input
  509.  
  510. extended_keyboard_chr:
  511.         MOV     AH, INPUT_CHR_NOECHO       ; Null character, get ready to read next character
  512.         INT     21H                        ; Get it
  513.         PUSH    ES                         ; Save ES
  514.         PUSH    CS                         ; Set ES to value in CS
  515.         POP     ES
  516.         PUSH    DI                         ; Save DI
  517.         MOV     CX,000FH                   ; Set counter to number of items in table 1
  518.         MOV     DI, offset [table1]        ; Set starting address of table 1
  519.         repnz SCASB                        ; Scan for occurrence of second character in table 1
  520.         POP     DI                         ; Restore DI
  521.         POP     ES                         ;    and ES
  522.         XCHG    CX,BX                      ; Let BX contain pointer to item found in table 1
  523.         ADD     BX,BX                      ; Double it
  524.         PUSH    CS:WORD PTR [BX+table2]    ; Index into table 2 for starting address of service code
  525.                                            ;    The value is pushed onto the stack to allow for the
  526.                                            ;    return (Without a corresponding call!)
  527.         MOV     BX,CX                      ; Restore original BX value
  528.         RET                                ; Execute the fake return
  529.  
  530.  
  531. ;***************************************************************************
  532. ; Individual service routines
  533. ;***************************************************************************
  534. ;*********************************************************************************** Escape Key
  535. escape_handling:                        ; Escape character here
  536.         CALL    home_key                ; Go to start of line
  537.         CALL    cntrl_end               ; Delete to end
  538.  
  539. restart_input:
  540.         POP     DI                      ; Pop the return address off of the stack
  541.         JMP     SHORT reinit_buffer     ; Jump to reinitialize buffer and read
  542.  
  543. normal_keyboard_chr:
  544.         CMP     AL, CNTL_BACKSPACE    ; Control Backspace?
  545.         JE      nkc1                  ; if so, go to backspace handling
  546.         CMP     AL, BACKSPACE         ; Backspace?
  547.         JNE     nkc2                  ; If not continue
  548.  
  549. nkc1:
  550.         JMP     backspace_handling    ; Backspace here, take care of it
  551.  
  552. nkc2:
  553.         CMP     AL, CR                ; Is it a carriage return?
  554.         JNE     nkc3                   ; If not continue
  555.         JMP     cr_key                ; Yes, go take care of it
  556.  
  557. nkc3:
  558.         CMP     AL, ESC               ; Is it an escape character
  559.         JE      escape_handling       ; If so, go take care of it
  560.  
  561.         CMP     AL, TAB               ; Bad code here                                              ** remove this **
  562.         JE      nkc4                  ; Bad code here                                              ** remove this **
  563.  
  564. inline_mod5:
  565. nkc4:   CMP     DI,0888H              ; Compare DI to max buffer size (modified in line in Begin_Dosed)
  566.         JB      printable_char        ; If less than max then continue with printable character
  567.         MOV     AL, BELL              ; Prepare to ring the bell
  568.         JMP     display_one_char      ; Do it
  569.  
  570.  
  571. ;*********************************************************************************** Non editing character
  572. printable_char:
  573.         AND     BP,0FFF7H             ; Turn off the no changes made flag
  574.         OR      BP,0002H              ; Turn on the changes made to this line flag
  575.         PUSH    AX                    ; Save AX
  576.         CALL    display_and_test      ; go display the character
  577.         MOV     DX,ES:[cursor_posn]   ; Place the current cursor position in DX
  578.         TEST    BYTE PTR ES:[kbd_flag], INSERT_ON_MASK   ; Is insert mode mask on?
  579.         JE      add_chr_to_inbuf      ; If not then branch around shift up string
  580.         PUSH    DI                    ; Save the DI register
  581.  
  582. shift_up:
  583.         CMP     DI,SI                 ; Are we pointing past the end?
  584.         JBE     end_shift_up          ; Have we decended to the original point?
  585.         MOV     AL,[BX+DI-01H]        ; Move this character in input buffer up
  586.         MOV     [BX+DI],AL            ;    one byte in memory
  587.         DEC     DI                    ; Next character down
  588.         JMP     SHORT shift_up        ; Return for more
  589.  
  590. end_shift_up:
  591.         POP     DI                    ; Restore original end of input buffer pointer
  592.         INC     DI                    ; Increment it by one
  593.         INC     SI                    ; Also increment the current character pointer
  594.         CALL    redisplay_line
  595.         DEC     SI                    ; Now decrement source so that it will look
  596.                                       ;    like normal overwrite to next code section
  597.  
  598. add_chr_to_inbuf:
  599.         POP     AX                    ; Restore AX
  600.         MOV     AH,AL                 ; Move the current character into AH
  601.         XCHG    AL,[BX+SI]            ; Put it into the input buffer
  602.         INC     SI                    ; Point to next character position
  603.         CMP     DI,SI                 ; Have we gone past the end
  604.         JNB     acti1                 ; If not then forget update of DI
  605.         MOV     DI,SI                 ; DI is now reset to SI (which was >)
  606.  
  607. acti1:
  608.         AND     AL,AH                 ; AND old character against new character
  609.         CMP     AL, BLANK             ; If both are printable then we are finished
  610.                                       ;    because we have coundn't have shortened
  611.         JNB     acti_ret              ;    the line with the overwrite.  (eg. A over ^E
  612.                                       ;    would shorten line by one character)
  613.         TEST    BYTE PTR ES:[kbd_flag], INSERT_ON_MASK  ; If insert mode was on then we
  614.         JNE     acti_ret              ;    are finished also because we have already
  615.                                       ;    printed the string
  616.         CMP     SI,DI                 ; Also we can forget if we are at the end of the line
  617.         JE      acti_ret              ; None of the above hold, and we may have trailing
  618.         JMP     note_shorter_change   ;    characters on the line that need to be blanked
  619.                                       ;    over. (caused by overwriting a ^x diagraph or a
  620.                                       ;    Tab character with a single character.)
  621. acti_ret:
  622.         RET
  623.  
  624.  
  625. ;*********************************************************************************** End key
  626. end_key:
  627.         TEST    BP,0008H               ; Have we made any changes to this buffer?
  628.         JE      move_to_end            ; If so then go ahead an position to end of line.
  629.         AND     BP,0FFF7H              ; No changes, lets now indicate that changes have been made,
  630.         OR      DI,DI                  ;    and restore the input buffer.  Start by checking DI for zero.
  631.         JNE     move_to_end            ; Go restore if something is there.
  632.         MOV     AL,[BX-01H]            ; Get the length of the string in the holding buffer.
  633.         CMP     [BX-02H],AL            ; Is it larger than the max buffer size?
  634.         JB      recycle_input          ; If so then we have problems and a restart is necessary.
  635.         MOV     AH,00H                 ; Zero out AH
  636.         XCHG    AX,DI                  ; Move the new length into DI
  637.         CMP     BYTE PTR [BX+DI], CR   ; Is there a carriage return here
  638.         JE      move_to_end            ; If so then go ahead and restore it
  639.  
  640. recycle_input:
  641.         JMP     restart_input          ; No, we must have garbage in the input buffer, go back and restart
  642.  
  643. move_to_end:
  644.         CALL    right_arrow     ; move over one character to the right
  645.         JB      move_to_end     ; keep going if not at end
  646.  
  647. error_return:
  648.         RET
  649.  
  650.  
  651. ;*********************************************************************************** Control home key
  652. cntrl_home:
  653.         PUSH    SI              ; Save the pointer into the input buffer
  654.         CALL    home_key        ; Move to start of line
  655.         POP     SI              ; Restore pointer
  656.         MOV     CX,DI           ; Set CX to character count in string and remove the
  657.         SUB     CX,SI           ;    characters from start of line to current position from count.
  658.         XOR     DI,DI           ; Clear out the DI register
  659.         PUSH    DI              ; Save it.                                                               ** get rid of this **
  660.         PUSH    CX              ;   and the new count of characters.
  661.         JCXZ    after_drop_down ; If the new count of characters is zero then nothing else to do.
  662.  
  663. drop_text_down:
  664.         MOV     AL,[BX+SI]      ; Get the current character
  665.         INC     SI              ; Advance source pointer to next character
  666.         MOV     [BX+DI],AL      ; Store it down into the next destination available
  667.         INC     DI              ; Increment the destination pointer
  668.         LOOP    drop_text_down  ;    and continue for the count
  669.  
  670. after_drop_down:
  671.         POP     DI                    ; Restore DI
  672.         POP     SI                    ;    and SI                                                             ** change this to xor SI,SI **
  673.         JMP     note_shorter_change   ; Now go redisplay line on screen
  674.  
  675.  
  676. ;*********************************************************************************** Control end key
  677. cntrl_end:
  678.         OR      BP,0002H                        ; Turn on the change to line flag
  679.         MOV     CX,CS:WORD PTR [inline_mod3+1]  ; Get the screen position of the last character in the screen
  680.  
  681. blank_to_end:
  682.         CMP     CX,ES:[cursor_posn]      ; Is the current screen position at the end of line?
  683.         JBE     after_blanking           ; If so then jump
  684.         CALL    display_blank            ; Display a blank
  685.         JMP     SHORT blank_to_end       ; and continue until end of line position on screen is reached
  686.  
  687. after_blanking:
  688.         MOV     DI,SI                    ; The new line length is current offset in the line
  689.         JMP     place_cursor             ; and now place the cursor on the screen
  690.  
  691.  
  692. ;*********************************************************************************** Control right arrow
  693. cntrl_right_arrow:                       ; Move right to start of next word
  694.         CALL    right_arrow              ; Move right one character
  695.         JNB     cra_ret                  ; If at the end then fall out of loop
  696.         CALL    check_non_by_alpha       ; Check for non-alpha/alpha combination (return issued from subroutine
  697.                                          ;    if the condition is satisfied)
  698.         JMP     SHORT cntrl_right_arrow  ; continue the cycle
  699.  
  700. cra_ret:
  701.         RET
  702.  
  703. check_non_by_alpha:
  704.         MOV     AL,[BX+SI]       ; Get character
  705.         CALL    check_alpha      ; See if this is an alphabetic character
  706.         JB      cnba_ret         ; If not then we are finished
  707.         MOV     AL,[BX+SI-01H]   ; Get previous character
  708.         CALL    check_alpha      ; Is this an alpha?
  709.         JNB     cnba_ret         ; If so then we are still not happy and must continue searching.
  710.         POP     AX               ; Pop off the fake return address if this location points
  711.                                  ;    to an alpha character and the previous one doesnt.
  712. cnba_ret:
  713.         RET
  714.  
  715. check_alpha:
  716.         OR      AL, LOWER_CASE_MASK  ; Or in lower case bit
  717.         CMP     AL, SMALLA           ; Is this the letter "a"?
  718.         JB      cnba_ret             ; It is less than the letter "a" ... return
  719.         CMP     AL, LEFT_CURLY_BRACE ; Is this the character "{"?  (one greater than "z")
  720.         CMC                          ; Complement Carry flag so its on if < "{"
  721.         RET
  722.  
  723. ;*********************************************************************************** Right arrow
  724. right_arrow:
  725.         CMP     SI,DI                      ; Are we past the last character
  726.         JNE     redisplay_char             ; If not then continue
  727.         RET
  728.  
  729. redisplay_char:
  730.         MOV     AL,[BX+SI]          ; Move the current character into AL
  731.         INC     SI                  ; Bump the pointer #U8z]ge9^Z
  732. into input buffer
  733.         CALL    display_and_test    ; Redisplay that character
  734.         STC                         ; Set the carry flag
  735.         RET
  736.  
  737. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  738. L0474:  CALL    right_arrow                    ;\                             ;;
  739.         JNB     L0482                          ; \                            ;;
  740.         MOV     AL,07H                         ;  \ This code is not called.  ;;
  741.         AND     AL, BYTE PTR ES:[cursor_posn]  ;  /                           ;;
  742.         JNE     L0474                          ; /                            ;;
  743. L0482:  RET                                    ;/                             ;;
  744. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  745.  
  746.  
  747. ;*********************************************************************************** Control left arrow
  748. cntrl_left_arrow:
  749.         CALL    left_arrow               ; Move left one character
  750.         JB      bt_ret                   ; Jump if we are at the end of the buffer
  751.         CALL    check_non_by_alpha       ; See if we are at the start of an alph character string.
  752.         JMP     SHORT cntrl_left_arrow   ; If not then loop (if we were then the return was issued from
  753.                                          ;    check_non_by_alpha)
  754.  
  755. ;*********************************************************************************** Backtab key
  756. backtab:
  757.         CALL    left_arrow    ; move left one character
  758.         JB      bt_ret        ; If at the start of the line then quit
  759.         MOV     AL,07H        ; set up the mask
  760.         AND     AL,DL         ; check to see if we are on an 8 byte column.
  761.         JNE     backtab       ; If not then continue left.
  762.  
  763. bt_ret:
  764.         RET
  765.  
  766.  
  767. ;*********************************************************************************** Left Arrow
  768. left_arrow:
  769.         OR      SI,SI                      ; Are we at the start of the line
  770.         STC                                ; Set the carry flag
  771.         JE      cnba_ret                   ; If so then do nothing
  772.         DEC     SI                         ; Move the input buffer pointer back one
  773.         CALL    decrement_col_row          ; Adjust the col row positon
  774.         CMP     BYTE PTR [BX+SI], TAB      ; Have we just run over a tab?
  775.         JE      back_over_tab              ; If so then go expand it
  776.         CMP     BYTE PTR [BX+SI], BLANK    ; Compare for printable character
  777.         JNB     la_end                     ; If we have one then jump to final section
  778.         CALL    decrement_col_row          ; Decrement col row one more time (for ^ character)
  779.         JMP     SHORT la_end               ; Finish up
  780.                                            ; Expand the tab character
  781. back_over_tab:
  782.         PUSH    SI                         ; Save the SI pointer into input buffer
  783.         MOV     CX,SI                      ; Set the count to its value
  784.         MOV     AL,CL                      ;    and also AL
  785.         MOV     AH,07H                     ;
  786.         JCXZ    no_prev_tabs               ; At start of line (no previous tab to align us)
  787.                                            ; See if we can find another tab in front of us to
  788.                                            ;    align us on screen (character after that tab
  789.                                            ;    would be properly aligned on 8 byte boundary.)
  790. align:
  791.         DEC     SI                         ; Decrement the pointer into input buffer
  792.         CMP     BYTE PTR [BX+SI], BLANK    ; Check for printable character
  793.         JNB     align_end                  ; If found cycle in loop
  794.         CMP     BYTE PTR [BX+SI], TAB      ; Have we succeded in finding another tab?
  795.         JE      sub_prev_char_cnt          ; If so then we know we are aligned so jump
  796.         DEC     AH                         ; No, this must be a control character diagraph (^x form)
  797.                                            ;    so we need to subract an additional character from the
  798. align_end:                                 ;    count of characters found so far.
  799.         LOOP    align                      ; Go back for more
  800.  
  801. no_prev_tabs:                              ; Ok, we only get here if there were no previous
  802.                                            ;    characters in input buffer or if there were no previous
  803.                                            ;    tabs in the buffer
  804.         SUB     AH,CS:[start_off]          ; Subtract out the screen bias position for location 0 of the
  805.                                            ;    input buffer pointer.
  806. sub_prev_char_cnt:
  807.         SUB     AH,AL                      ; These two statements remove the count of all previous characters
  808.         ADD     CL,AH                      ;    in the buffer (either to tab boundary or start of line).
  809.                                            ;    Additional diagraph hats "^" have been previously subtracted
  810.                                            ;    from AH.
  811.         AND     CL,07H                     ; take modulo 8
  812.         JE      end_jump_tab               ; Did this tab expand into only one blank (remember we've already
  813.                                            ;    moved over one!), if so jump
  814. jump_tab:
  815.         CALL    decrement_col_row          ; Calculate new column and row on screen
  816.         LOOP    jump_tab
  817.  
  818. end_jump_tab:
  819.         POP     SI                         ; Restore input buffer pointer
  820.  
  821. la_end:
  822.         CLC                                ; Clear the carry flag
  823.         JMP     SHORT place_cursor         ; Go place the cursor on the screen
  824.         NOP
  825.  
  826.  
  827. ;*********************************************************************************** Home key
  828. home_key:                                  ; home key service begins here
  829.         CALL    left_arrow                 ; move over one
  830.         JB      pc_ret                     ; jump if back at start
  831.         JMP     SHORT home_key             ; Not there yet, keep going
  832.  
  833.  
  834. ;*********************************************************************************** Backspace key
  835. backspace_handling:                        ; backspace handling begins here
  836.         CALL    left_arrow                 ; first just move over one character
  837.         JB      pc_ret                     ; If we are already at the start of the line
  838.                                            ;    then we neednt continue
  839.  
  840. ;*********************************************************************************** Delete Key
  841. del_key:                                   ; Delete key handling begins here
  842.         OR      DI,DI                      ; Is the string length zero?
  843.         JE      pc_ret                     ; If so go to end
  844.         CMP     SI,DI                      ; Are we past the end of the string?
  845.         JE      pc_ret                     ; If so go to end
  846.         PUSH    SI                         ; Save the SI pointer to input buffer
  847.  
  848. shift_down:
  849.         CMP     SI,DI                      ; Are we past the end:
  850.         JE      after_shift_down           ; If so, finish up
  851.         MOV     AL,[BX+SI+01H]             ; Get next character up
  852.         MOV     [BX+SI],AL                 ; then shift it down into this slot
  853.         INC     SI                         ; Increment the input buffer pointer
  854.         JMP     SHORT shift_down           ;    and cycle
  855.  
  856. after_shift_down:
  857.         POP     SI                         ; Restore the input text buffer pointer
  858.         DEC     DI                         ; Decrement the length of the input buffer string
  859.  
  860. note_shorter_change:
  861.         OR      BP,0003H                   ; Indicate that we have changed and potentially shortened the string.
  862.  
  863. redisplay_line:
  864.         AND     BP,0FFF7H
  865.         PUSH    SI                       ; Save the pointer into the input buffer
  866.  
  867. display_next_char:
  868.         CMP     SI,DI                    ; Are we past the end of the string?
  869.         JNB     after_display_char       ; If so dont display
  870.         MOV     AL,[BX+SI]               ; Get the character from the input buffer
  871.         CALL    display_and_test         ; send it to the display
  872.         INC     SI                       ; update buffer pointer
  873.         JMP     SHORT display_next_char  ; continue to end
  874.  
  875. after_display_char:
  876.         CALL    set_cursor                      ; Set type of cursor, AX returns with current cursor location (end of line)
  877.         TEST    BP,0001H                        ; Is the old line longer?
  878.         JE      after_blank_pad                 ; If not then forget blanking the tail
  879.         XCHG    AX,CS:WORD PTR [inline_mod3+1]  ; Put current cursor positon in end of line indicator and
  880.                                                 ;    save that value for blanking operation
  881.         XCHG    AX,CX                           ; Put former end of line position in CX
  882.  
  883. add_blank_pad:
  884.         CALL    display_blank            ; Display a blank
  885.         CMP     CX,ES:[cursor_posn]      ; Is current cursor position now at end of line
  886.         JNBE    add_blank_pad            ; If not, then continue blanking loop.
  887.  
  888. after_blank_pad:
  889.         POP     SI
  890.  
  891. place_cursor:
  892.         MOV     AH, SET_CURSOR_POSN      ; Load AH for Bios call
  893.         PUSH    BX                       ; Save BX and CX registers
  894.         PUSH    CX
  895.         MOV     CS:[current_col],DL     ; Record current column position
  896.         MOV     BH,00H
  897.         INT     10H                     ; Call bios for service
  898.         POP     CX                      ; Restore registers
  899.         POP     BX
  900.  
  901. pc_ret:
  902.         RET
  903.  
  904.  
  905. ;*********************************************************************************** Up Arrow
  906. up_arrow:                               ; Up arrow service starts here
  907.         STD                             ; Set direction flag to decrement
  908.  
  909. ;*********************************************************************************** Down Arrow
  910. down_arrow:                             ; Down arrow service starts here
  911.         AND     BP,0FFF7H
  912.         CALL    home_key                ; Go to beginning of line
  913.         CALL    cntrl_end               ; Delete to end of line
  914.  
  915. da1:
  916.         PUSH    ES                      ; Save ES register
  917.         PUSH    DS                      ; Set ES to DS
  918.         POP     ES
  919.         PUSH    CS                      ; Set DS to CS
  920.         POP     DS
  921.         MOV     SI,DS:[last_entry]      ; Get pointer to first byte of current string in
  922.                                         ;    input buffer (from text buffer)
  923.         LODSB                           ; Obtain the character
  924.         LEA     DI,[BX-01H]             ; Load DI with the offset of the length character
  925.                                         ;    of the input buffer
  926.         MOV     CX, TEXT_BUFFER_SIZE    ; Set counter to look at each location in the text buffer
  927.  
  928. search_for_len_byte:
  929.         CALL    get_char                ; Get a character from the text holding buffer
  930.         TEST    AL,  LENGTH_BYTE_MASK   ; Is it a length byte?
  931.         LOOPZ   search_for_len_byte     ; Nope, go back and try again
  932.         CLD                             ; Yep, clear the direction flag
  933.         JNE     found_a_len_byte        ; Jump if we found a length byte
  934.         PUSH    ES                      ; Restore DS
  935.         POP     DS
  936.         POP     ES                      ; Restore ES
  937.         JMP     restart_input
  938.  
  939. found_a_len_byte:
  940.         AND     BP,0FFF1H                         ; Indicate new line from holding buffer, and no changes made to it.
  941.         CALL    get_char                          ; Get a dummy character to readjust the SI pointer
  942.         TEST    BYTE PTR [SI],  LENGTH_BYTE_MASK  ; Is next location a length byte
  943.         JNE     recover_string                    ; If so (then down arrow issued) jump to recover string
  944.         DEC     SI                                ; No, an up arrow was issued and we need to back SI down two bytes to
  945.                                                   ;   set up for next get_char to be the length byte.
  946.         CALL    swap_and_get_tp                   ; Back a-one
  947.         DEC     SI
  948.         CALL    swap_and_get_tp                   ; and a-two
  949.  
  950. recover_string:
  951.         MOV     DS:[last_entry],SI       ; Load the address of the last accessed buffer string
  952.         CALL    get_char                 ; Get the length character from holding buffer
  953.         AND     AL, LENGTH_OFF_MASK      ; Mask off the length byte identifier
  954.         MOV     AH, BYTE PTR ES:[DI-01H] ; Place Max buffer size in AH
  955.         CMP     AL,AH                    ; Is text string smaller than max buffer size?
  956.         JB      continue_recovery        ; If so then continue recovery
  957.         MOV     AL,AH                    ; Uh-oh, take the max buffer size as the count of chars to restore
  958.  
  959. continue_recovery:
  960.         STOSB                           ; Save the length count
  961.         CBW                             ; Get rid of high portion of AX
  962.         XCHG    AX,CX                   ; Place the count in CX
  963.         PUSH    CX                      ;    and save it for later
  964.  
  965. load_chr_and_display:
  966.         CALL    get_char                ; Get a character from the holding buffer
  967.         STOSB                           ; Store this character in the input buffer
  968.         CALL    display_and_test        ; Display this character
  969.         LOOP    load_chr_and_display    ; Continue until all characters are done
  970.         POP     DI                      ; Place the count of the number of characters in the
  971.                                         ;    string into DI
  972.         MOV     SI,DI                   ; Require the current pointer to be just past the end
  973.         PUSH    ES                      ; Restore DS
  974.         POP     DS
  975.         POP     ES                      ; Restore ES
  976.  
  977. lcad_ret:
  978.         RET
  979.  
  980. ;*********************************************************************************** Control Page Down
  981. cntrl_page_down:
  982.         TEST    BP,0006H             ; Are we on the original line or have we made mods
  983.         JNE     lcad_ret             ; If so then do nothing
  984.         PUSH    DS                   ; Save some registers
  985.         PUSH    ES
  986.         PUSH    BX
  987.         CALL    home_key             ; Move to start of line
  988.         CALL    cntrl_end            ; Delete to the end of the line
  989.         PUSH    CS                   ; Set ES register to CS                                                ** change to mov **
  990.         POP     ES
  991.         PUSH    CS                   ; Set DS register to CS
  992.         POP     DS
  993.         MOV     DI,DS:[last_entry]   ; Get address of last string accessed in holding buffer
  994.         PUSH    DI                   ; Save it.
  995.         MOV     SI,DI                ; Point the source index to it.
  996.  
  997. skip:
  998.         CALL    get_char             ; Get a character from the text buffer
  999.         CMP     AL, CR               ; Is it a carriage return?
  1000.         JNE     skip                 ; If n~r~_ot keep going
  1001.  
  1002. move_down:
  1003.         CMP     SI,DS:[next_entry]   ; Are we at the next available location in buffer
  1004.         JE      pad_crs              ; If so then break out of loop
  1005.         CALL    get_char             ; Get this character
  1006.         CALL    save_char            ;    and move it down in the holding buffer.
  1007.         JMP     SHORT move_down      ; Continue the loop.
  1008.  
  1009. pad_crs:
  1010.         MOV     AL, CR               ; Load AL with a carriage return
  1011.         MOV     [DI],AL              ; and into the buffer
  1012.         MOV     BX,DI                ; Now reset the base pointer one beyond last string in holding buffer.
  1013.         XCHG    BX,DS:[next_entry]   ; Put the old value in BX and the new value in place
  1014.         POP     SI                   ; Restore the pointer to last string accessed
  1015.  
  1016. continue_pad_cr:
  1017.         CMP     BX,DI                   ; Are we at the old next_available slot yet?
  1018.         JE      after_pad_cr            ; If yes the break out
  1019.         CALL    save_char               ; No, save the carriage return
  1020.         JMP     SHORT continue_pad_cr   ; Keep going
  1021.  
  1022. after_pad_cr:
  1023.         DEC     SI                      ; Point to just before this entry (so Down arrow will pick it up)
  1024.         MOV     DS:[last_entry],SI      ; Save it as last accessed text entry
  1025.         POP     BX                      ; Restore registers.
  1026.         POP     ES
  1027.         POP     DS
  1028.         JMP     da1                     ; Go perform a down arrow operation
  1029.  
  1030. ;*********************************************************************************** Carriage Return
  1031. cr_key:
  1032.         AND     BYTE PTR ES:[kbd_flag], INSERT_OFF_MASK  ; Turn off insert mode
  1033.         CALL    set_cursor               ; Change the cursor on the screen
  1034.         POP     AX                       ; Pop the fake return address off the stack (so we really return)
  1035.         CALL    move_to_end              ; Move the cursor to the end of the line
  1036.         MOV     AL, CR                   ; Move a CR into AL
  1037.         CALL    display_one_char         ; Display it
  1038.         MOV     [BX+DI],AL               ; Add the CR to the input buffer
  1039.         MOV     AX,DI                    ; Move the length into AX
  1040.         MOV     [BX-01H],AL              ; Now move it into the length byte of the input buffer
  1041.         MOV     SI,BX                    ; Point the Source index to the input buffer
  1042.         CMP     AL,02H                   ; Are there at least two characters?                         ** remove this? **
  1043.         JBE     crk_ret                  ; If not then just forget the save
  1044.         PUSH    CS                       ; Set ES to value in CS
  1045.         POP     ES
  1046.         INC     WORD PTR CS:[last_entry] ; Bump the pointer to the strings location in the text buffer
  1047.         TEST    BP,0002H                 ; Have changes been made to this line?
  1048.         JE      crk_ret                  ; If not then we are through
  1049.         MOV     DI,CS:[next_entry]       ; Point the destination to the next available slot
  1050.         OR      AL,  LENGTH_BYTE_MASK    ; Add in the length byte bit mask
  1051.  
  1052. save_string:
  1053.         CALL    save_char                ; Add it to the holding buffer
  1054.         CMP     AL, CR                   ; Is this a carriage return?
  1055.         JE      after_save_string        ; If so, break out of loop
  1056.         LODSB                            ; Get the next character from the input buffer
  1057.         JMP     SHORT save_string
  1058.  
  1059. after_save_string:
  1060.         MOV     CS:[next_entry],DI       ; Save the new pointer to the text holding buffer
  1061.  
  1062. omit_partial_string:
  1063.         CMP     CS:[DI],AL                 ; Is it a carriage return?
  1064.         JE      after_omit_partial         ; If so we are finished
  1065.         CALL    save_char                  ; No, that means there is a partial string here
  1066.         JMP     SHORT omit_partial_string  ;    so fill with CRs until next CR is found
  1067.  
  1068. after_omit_partial:
  1069.         MOV     CS:[last_entry],DI
  1070.  
  1071. crk_ret:
  1072.         RET
  1073.  
  1074. get_char:                        ; Obtain a character from the text holding buffer
  1075.         CALL    swap_and_get_tp  ; First we must reverse SI and DI pointers
  1076.         LODS    CS:[SI]          ; Load the character from the text holding buffer into AL
  1077.  
  1078. swap_and_get_tp:                 ; Reverse SI and DI pointers because
  1079.         XCHG    SI,DI            ;    get_text_pointer assumes that DI indexes
  1080.         CALL    get_text_pointer ;    into the text holding buffer and not SI
  1081.         XCHG    SI,DI            ; Verify legal pointer into holding buffer
  1082.         RET
  1083.  
  1084. save_char:                        ; Add a character to the text holding buffer
  1085.         CALL    get_text_pointer  ; Verify correctness of pointer
  1086.         STOSB                     ; Move the character in AL to the text holding buffer
  1087.  
  1088. get_text_pointer:                   ; Obtain a legal pointer into the text holding buffer
  1089.         CMP     DI,CS:[buffer_bot]  ; Is the current pointer too small?
  1090.         JNB     gtp1                ; If not, then continue
  1091.         MOV     DI,CS:[buffer_top]  ; Yes, set to upper limit
  1092.         DEC     DI                  ;    and decrement one
  1093.  
  1094. gtp1:
  1095.         CMP     DI,CS:[buffer_top]  ; Is the current pointer too big?
  1096.         JB      gtp_ret             ; If not jump to end
  1097.         MOV     DI,CS:[buffer_bot]  ; Yes, set to lower limit
  1098.  
  1099. gtp_ret:
  1100.         RET
  1101.  
  1102. ;*********************************************************************************** Control Page Up
  1103. cntrl_page_up:                         ; Control Page Up service begins here
  1104.         CALL    home_key               ; Go to start of line
  1105.         CALL    cntrl_end              ; And delete forward
  1106.         PUSH    DS                     ; Save DS
  1107.         MOV     AX,CS                  ; Set DS and ES to value in CS
  1108.         MOV     DS,AX
  1109.         MOV     ES,AX
  1110.         MOV     DI,DS:[buffer_bot]     ; Get base address of text buffer
  1111.         MOV     DS:[last_entry],DI     ; Set current pointer into text buffer to base
  1112.         MOV     DS:[next_entry],DI     ; Set next new pointer into text buffer to base
  1113.         MOV     CX, TEXT_BUFFER_SIZE   ; Set count to size of text holding buffer
  1114.         MOV     AL, CR                 ; Set AL with CR and fill holding buffer
  1115.         repz STOSB                     ;    with carriage returns
  1116.         POP     DS                     ; Restore DS
  1117.         JMP     restart_input
  1118.  
  1119. ; Data area
  1120. start_off    db      0h
  1121. current_col  db      0h
  1122. last_entry   dw      TEXT_BUFFER_START
  1123. next_entry   dw      TEXT_BUFFER_START
  1124. buffer_bot   dw      TEXT_BUFFER_START
  1125. buffer_top   dw      TEXT_BUFFER_END
  1126. aux_last     dw      AUX_BUFFER_START
  1127. aux_next     dw      AUX_BUFFER_START
  1128. aux_bot      dw      AUX_BUFFER_START
  1129. aux_top      dw      AUX_BUFFER_END
  1130.  
  1131. initialize:
  1132.  
  1133. DOSED   ENDP
  1134. CSEG    ENDS
  1135.         END  DOSED
  1136.