TED2.ASM
上传用户:liaison
上传日期:2007-01-05
资源大小:31k
文件大小:77k
- NAME TED
- PAGE 58,132
- TITLE TED -- the Tiny EDitor
- ;=======================================================================
- ; TED.ASM -- The Tiny EDitor.
- ; PC Magazine * Tom Kihlken * 11/15/88
- ;
- ; See the article "The tiniest editor you'll ever need" by Tom Kihlken,
- ; in the November 15, 1988 issue of PC Magazine for more detail than is
- ; presented here. Portions of this text are excerpted from that article.
- ; The source listing, itself, was copied directly from that article and
- ; altered as appropriate to add comments or change or improve the program.
- ; The use of self-modifying code for "NO_DESNOW" is discussed in the article.
- ; SEGment register usage have been cleaned up to reduce the size of the code.
- ;
- ; TED follows normal text conventions: pressing the <Enter> key actually
- ; adds two characters, Carriage-return (ASCII 13) and Line-feed (ASCII 10),
- ; also known as a "hard carriage return". The <Tab> key inserts the ASCII 9
- ; tab character, and advances the screen cursor to the next column that is
- ; an even multiple of eight. The <Backspace> key deletes the character to
- ; its immediate left ("destructive" backspace) and combines two lines if it
- ; is pressed while in the first column. The Backspace code (Ctrl-H) may be
- ; entered in the file as a control code. TED2 allows the ASCII codes for
- ; Carriage-Return (Ctrl-M) and Line-feed (Ctrl-J) to independently be entered
- ; into the file as control codes. Because of this, TED2 rigidly enforces
- ; a convention that once the <Ctrl-M><Ctrl-J> pair is formed it becomes an
- ; End-of-line marker, and may not be separated again.
- ;
- ; Like DOS, TED lets you enter any character (except <Nul>, value 00) by
- ; holding down the Alt key, typing the decimal value of its ASCII code on
- ; the numeric keypad, then releasing Alt. This gives you access both to
- ; nonprinting codes below ASCII 32 and to the upper-order (ASCII 128 to 255)
- ; characters in the extended IBM set. TED2 allows the <Nul> code to be
- ; entered by pressing the <Shft-F1> key.
- ;
- ; NOTE: Unassigned keyboard codes are treated as no-operations.
- ;
- ; The TED Keypad commands are:
- ; Key Description
- ; Up Arrow Moves cursor up one row
- ; Down Arrow Moves cursor down one row
- ; Left Arrow Moves cursor left one column
- ; Right Arrow Moves cursor right one column
- ; PgUp Moves text window up one page
- ; PgDn Moves text window down one page
- ;>Home Moves cursor to start of row (if at home, next up)
- ;>End Moves cursor to end of row (if at end, next end down)
- ; Ins Toggles insert/overstrike mode
- ; Del Deletes character (right) at cursor (saved in UnDo)
- ; Backspace Deletes character (left) at cursor (not saved in UnDo)
- ; Ctrl-PgUp Moves to top of file
- ;>Ctrl-Home Moves to top of file (alias)
- ; Ctrl-PgDn Moves to bottom of file
- ;>Ctrl-End Moves to bottom of file (alias)
- ; Ctrl-Right Arrow Moves text window right eight columns
- ; Ctrl-Left Arrow Moves text window left eight columns
- ;
- ; Alt-S Search Search for (case insensitive) character string
- ; Alt-A Search Again Search again for string
- ; Alt-D Del EOL Deletes from cursor to the end of line
- ;
- ; The TED Editing Functions are:
- ; Key Function Operation
- ; F1 Help Help screen
- ; ShftF1 <Nul> Enters the <Nul> code (value 00) in the file
- ; F2 Exit Save changes and exit (creates a .BAK file)
- ; ShftF2 Quit Exit without saving changes
- ; F3 Print Prints the marked text
- ; F4 Mark Toggles mark state on/off
- ; F5 Cut Moves marked text to paste buffer
- ; ShftF5 Paste Inserts contents of paste buffer (64K char's max)
- ; F6 Search Search for (case insensitive) character string
- ; ShftF6 Search Again Search again for string
- ; F7 UnDo Replaces recently DELeted characters (256 char's max)
- ; F8 Del EOL Deletes from cursor to the end of line
- ; ShftF8 Del L Deletes the current line (MultiEdit)
- ; F9 Del L Deletes the current line
- ; F10 Udel L Inserts the last deleted line (256 char's max)
- ;
- ; In addition to the 64K Text buffer (where the edit file is maintained),
- ; there are three other important buffers, as indicated above.
- ; 1.) The paste buffer is a 64K character buffer used for MARK/CUT/PASTE of
- ; sections of the file.
- ; 2.) The line buffer is a 256 character buffer used to save the last
- ; deleted line of text (used with F8, F9 and F10).
- ; 3.) The UnDo buffer is a 256 character buffer used to save the just
- ; deleted characters at the current cursor location. It works with
- ; the "DEL" key, but only the last character with the "Backspace" key.
- ; It also saves overwritten characters in the Overstrike mode.
- ; Deletions are restored with "F7" UnDo.
- ;
- ; NOTE: There is a severe subroutine nesting violation in the TED key scan
- ; routine. BAD_KEY from within the keyboard scanning loop is a junp to
- ; read next key. The BAD_KEY subroutine calls through the DISPATCH_TABLE
- ; do not have a corresponding return to equalize the stack. This was
- ; partially compensated for by making the stack humongous. TED 1.0 as
- ; published in PC Magazine could eventually overflow the stack and crash the
- ; system. TED2 has corrected this problem by making a stub subroutine for
- ; the DISPATCH_TABLE BAD_KEY subroutine CALLs.
- ;
- ; TED was modified by James E. Galbraith, Dec 18, 1988.
- ; The changes are of several types. Compatability with other editors.
- ; Correction of errors and questionable code. Reordering of program modules
- ; to make it easier to follow the listing. Addition of meaningful comments.
- ; These modifications include:
- ; Change F2 "UnDo" to "Exit" (for BSE compatibility).
- ; Change F7 "Exit" to "UnDo".
- ; Make CTRL-HOME alias to CTRL-PGUP, to home the cursor (for BSE).
- ; Make CTRL-END alias to CTRL-PGDN, cursor to end of file (for BSE).
- ; JMP instructions outside modules instead of CALL/RETurn are commentd.
- ; Assignment of DS was sometimes ambiguous.
- ;
- ; Modified by James E. Galbraith, June 1989.
- ; The changes are in two groups. Those taken from TEDPLUS (apparently also
- ; written by Tom Kihlken), which was acquired from a bulletin board service,
- ; and my own changes.
- ; Add SEARCH and SEARCH AGAIN as F6 and Shft-F6, from TEDPLUS.
- ; Delete CPM style Ctrl-Z End-of-file code, from TEDPLUS.
- ; "Enter any key code" from TEDPLUS was included, but not like TEDPLUS
- ; End-of-line was changed to CR-LF as in TEDPLUS. CR or LF codes may be
- ; entered separately.
- ; My own changes are:
- ; Close the source file if it has been opened. This was not done by TED.
- ; Add a HELP screen as <F1>, move QUIT to <Shft-F2>.
- ; Fix the SEARCH inverse video to turn off when any key is pressed.
- ; Add DOS version check, needs version 2.0 or higher to run.
- ; Add a program checksum test for verification of file integrity.
- ; Add <Alt-S> as alias for <F6> SEARCH (usage in BSE editor).
- ; Add <Alt-A> as alias for <Shft-F6> SEARCH AGAIN (usage in BSE editor).
- ; Add <Alt-D> as alias for <Shft-F8>, Delete to end of line.
- ; Add <Shft-F8> as alias for <F9>, Delete Line (for future expansion).
- ; If the file has not been altered, don't prompt for save or quit.
- ; On QUIT, accept a CR as confirmation of intention to abandon file.
- ; Add <Shft-F1> as key to enter the <Nul> character, 00.
- ; If a CR and LF code are made to be ajacent, they become an EOL marker,
- ; and may not then be separated. This can occur in several ways that
- ; all include entering the codes <Crtl-M> and <Ctrl-J>.
- ; A key entry will interrupt a screen update that is in progress.
- ;
- ; Assemble the TED2.ASM source file to TED2.COM by using the MASM.EXE assembler,
- ; the linker LINK.EXE, and the file conversion utility EXE2BIN.EXE, as follows:
- ; The checksum byte can be obtained with TEST.BAT (included with TED2.ASM).
- ;
- ; MASM TED2;
- ; LINK TED2;
- ; EXE2BIN TED2 TED2.COM
- ;-----------------------------------------------------------------------
- CSEG SEGMENT
- ASSUME CS:CSEG, DS:CSEG, ES:CSEG
- ORG 0100H
- START:
- JMP BEGIN
- ;-----------------------------------------------------------------------
- ; Local data area in CSEG.
- ;-----------------------------------------------------------------------
- ; ASCII character values used in the program.
- TAB EQU 9
- CR EQU 13
- LF EQU 10
- CRLF EQU 0A0DH
- ; Character strings and data
- COPYRIGHT DB "TED 1.0 (C) 1988 Ziff Communications Co.,"
- DB "PC Magazine, 11/15/88, by Tom Kihlken"
- DB CR,LF,"TED 2.1, 9/12/89, by James E. Galbraith"
- DB CR,LF,"$"
- ;(JEG)
- HELP_SCREEN DB 9,9,'TED - the Tiny EDitor (any key to edit)',CR
- DB LF,LF,9,'F1 - Help',9,9,9,'Shft-F1 - <NUL> char'
- DB CR,LF,9,'F2 - Exit and save',9,9,'Shft-F2 - Quit'
- DB CR,LF,9,'F3 - Print marked',9,9,'Shft-F3 - Form-feed'
- DB CR,LF,9,'F4 - Mark toggle'
- DB CR,LF,9,'F5 - Cut marked',9,9,9,'Shft-F5 - Paste'
- DB CR,LF,9,'F6 - String search',9,9,'Shft-F6 - '
- DB 'Search again'
- DB CR,LF,9,'F7 - Undo <Del> or Ovr'
- DB CR,LF,9,'F8 - Delete to EOL' ;** ,9,9,'Shft-F8 - '
- ;** DB 'Delete Line'
- DB CR,LF,9,'F9 - Delete Line'
- DB CR,LF,9,'F10 - Un-Delete line',LF
- DB CR,LF,9,'Ctrl-L/R arrow - Move window'
- DB CR,LF,9,'Ctrl-Home - to top'
- DB CR,LF,9,'Ctrl-End - to EOF',LF
- DB CR,LF,9,'Esc - From Exit'
- DB CR,LF,'$',7,1AH
- ;from JEG and TEDPLUS
- PROMPT_STRING DB "1Help",0 ;F1
- DB "2Exit",0 ;F2
- DB "3Print",0 ;F3
- DB "4Mark",0 ;F4
- DB "5Cut",0 ;F5
- DB "6Search",0 ;F6
- DB "7UnDo",0 ;F7
- DB "8Del EOL",0 ;F8
- DB "9Del L",0 ;F9
- DB "10Udel L",0,0 ;F10
- PROMPT_LENGTH = $ - OFFSET PROMPT_STRING
- FILE_TOO_BIG DB "File too big$"
- READ_ERR_MESS DB "Read error$"
- MEMORY_ERROR DB "Not enough memory$"
- ;(JEG)
- CHEK_SUM_MESS DB "TED altered$"
- DOS_2_MESS DB "Needs DOS 2.0$"
- VERIFY_MESS DB "Lose Changes (Y)?",0
- SAVE_MESS DB "Save as: ",0
- DOT_$$$ DB ".$$$",0
- DOT_BAK DB ".BAK",0
- ;from TEDPLUS, string search
- SRCH_PROMPT DB "SEARCH> ",0
- ;SRCH_MAX DB 66 ;(moved to file end to reduce file size)
- ;SRCH_SIZ DB 0
- ;SRCH_STR DB 66 DUP (0)
- SRCH_FLG DB 0 ;0=normal, 1=search successful (inverse)
- SRCH_END DW 0
- SRCH_BASE DW 0
- SRCH_CLR DB 0F0H ;244
- DIRTY_BITS DB 03H ;1=update screen, 2=cursor 4=cur. line
- DIRTY_FILE DB 0 ;0=file not altered, FF=file altered
- NORMAL DB 07H ;video attribute bits
- INVERSE DB 70H ;video (inverse)
- LEFT_MARGIN DB 0 ;column number of screen left margin
- MARGIN_COUNT DB 0
- INSERT_MODE DB 01H ;1=INSert, 0=Overstrike, 2or3=Read Only
- INSERT_CODE DB 'OIRR' ;indexed code for display screen
- MARK_MODE DB 0 ;toggle, FF=MARK is on.
- ROWS DB 23 ;Rows available on display screen
- SAVE_COLUMN DB 0
- SAVE_ROW DB 0
- LINE_FLAG DB 0
- EVEN ;"word align" (for 16-bit bus accesses)
- NAME_POINTER DW 81H ;offset of command tail in PSP
- NAME_END DW 81H ;end of tail
- VIDEO_STATUS_REG LABEL DWORD ;(alias for use by LES instruction)
- STATUS_REG DW 0 ;video status register offset
- VIDEO_SEG DW 0B000H ;video segment, Mono=0B000, other 0B800
- LINE_LENGTH DW 0 ;number of bytes in current line
- UNDO_LENGTH DW 0 ;number of DELeted bytes in UnDo buffer
- CURS_POSN DW 0 ;Cursor, Hi is row, Low is column
- MARK_START DW 0FFFFH ;MARK text for CUT/PASTE or Print
- MARK_END DW 0
- MARK_HOME DW 0
- TOP_OF_SCREEN DW 0 ;address in text file of Top-of-screen
- CURSOR DW 0 ;address in text file of cursor
- LAST_CHAR DW 0 ;address of last character in file.
- COLUMNSB LABEL BYTE ;alias BYTE definition
- COLUMNS DW 0
- PASTE_SEG DW 0 ;segment address of PASTE buffer
- PASTE_SIZE DW 0 ;size of block in PASTE buffer
- PAGE_PROC DW 0 ;pointer used by PGUP and PGDN
- EXIT_CODE DW 4C00H ;DOS INT 21H, Func 4CH, exit with code
- OLDINT24 DD 0 ;pointer to DOS critical error handler
- DISPATCH_BASE EQU 59 ;initial offset for a PASCAL type CASE list
- DISPATCH_TABLE DW HELP ;59;F1, Help screen (common usage)
- DW EXIT ;60;F2, Save changes and exit (from BSE)
- DW PRINT ;61;F3, Print the marked text
- DW MARK ;62;F4, Toggle mark state on/off
- DW CUT ;63;F5, Move marked text to buffer
- DW FIND_STR ;64;F6, Search for text string
- DW UNDO ;65;F7, Replace recently deleted chars
- DW DEL_EOL ;66;F8, Delete from cursor to EOL
- DW DEL_L ;67;F9, Delete the current line
- DW UDEL_L ;68;F10, Insert the last deleted line
- DW BAD_KEY ;69;(NumLock)
- DW BAD_KEY ;70;(ScrollLock)
- DW HOME_KEY ;71;Home/7
- DW UP ;72;Up/8
- DW PGUP ;73;PgUp/9
- DW BAD_KEY ;74;(-)
- DW LEFT ;75;Left/4
- DW BAD_KEY ;76;(5)
- DW RIGHT ;77;Right/6
- DW BAD_KEY ;78;(+)
- DW END_KEY ;79;End/1
- DW DOWN ;80;Down/2
- DW PGDN ;81;PgDn/3
- DW INSERT ;82;Ins/3
- DW DEL_CHAR ;83;Del/.
- DW NUL_CHAR ;84;Shft-F1 -- Add NUL character to file
- DW ABORT ;85;Shft-F2 -- Quit and abandon changes
- DW PRINT_FF ;86;Shft-F3 -- Print a form-feed character
- DW BAD_KEY ;87;Shft-F4
- DW PASTE ;88;Shft-F5 -- Insert contents of Paste buffer
- DW FIND_STR ;89;Shft-F6 -- Search again for string
- DW BAD_KEY ;90;Shft-F7
- DW DEL_L ;91;Shft-F8 -- Delete line (Multi-Edit)
- DISPATCH_END EQU 92
- ;--------------------------------
- ; gap in keyboard scan code assignments
- ;--------------------------------
- DISP_CURS_BASE EQU 115
- DW SH_LEFT ;115;Ctrl-Left arrow
- DW SH_RIGHT ;116;Ctrl-Right arrow
- DW BOTTOM ;117;Ctrl-End
- DW CTRL_PGDN ;118;Ctrl-PgDn
- DW TOP ;119;Ctrl-Home
- DISP_CURS_END EQU 120
- ;** DW CTRL_PGUP ;132;Ctrl-PgUp
- ;---------------------------------
- ; The following constant is a machine instruction that removes the CGA desnow
- ; delay. It is inserted into the code for EGA, VGA, and mono displays.
- ; See the article in PC-Magazine for further discussion.
- NO_DESNOW = (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256 + 0EBH ;opcode JMP SHORT
- ;=======================================================================
- ; We start by initialize the display, then allocate memory for the file
- ; and paste segments. Parse the command line for the filename, if one was
- ; input, read in the file. Finally set the INT 23 and 24 vectors.
- ;-----------------------------------------------------------------------
- BEGIN:
- MOV AH,30H ;get DOS version (JEG new)
- INT 21H
- CMP AL,2
- JAE DOS_2_UP
- MOV EXIT_CODE,0 ;is DOS version 1, exit with function 0.
- MOV DX,OFFSET DOS_2_MESS ;message "Needs DOS 2.0"
- ;**short JMP EXIT_TO_DOS
- JMP SHORT EXIT_22_DOS ;(saves a byte)
- ;-----------------------
- DOS_2_UP:
- ;JEG new -- program code checksum test
- MOV SI,100H ;start of program file.
- MOV SP,SI ;set stack pointer to top of PSP.
- MOV CX,OFFSET CHEK_SUM_BYT - 0100H ;size of program file.
- MOV AL,CHEK_SUM_BYT ;load checksum correction factor byte.
- CHKSUM_LOOP: ADD AL,[SI] ;add all program code bytes together.
- INC SI
- LOOP CHKSUM_LOOP
- CMP AL,0 ;is program checksum zero?
- JZ CHEKSUM_IS_OK ;yes, continue with program
- NEG AL ;make error into correction factor.
- MOV BYTE PTR EXIT_CODE,AL ;save errorlevel code for exit.
- MOV DX,OFFSET CHEK_SUM_MESS ;message "TED altered".
- ;**short JMP EXIT_TO_DOS ;error message and exit to DOS
- ;EXIT_22_DOS: JMP SHORT EXIT_2_DOS ;error message and exit to DOS
- EXIT_22_DOS: JMP EXIT_2_DOS ;error message and exit to DOS
- ;-----------------------
- CHEKSUM_IS_OK:
- XOR AX,AX
- MOV DS,AX ;zero DS
- ASSUME DS:NOTHING
- MOV BL,10H
- MOV AH,12H ;get EGA info
- INT 10H
- CMP BL,10H ;did BL change?
- JE NOT_EGA ;if not, no EGA in system
- TEST BYTE PTR DS:[0487H],8 ;is EGA active?
- JNZ NOT_EGA
- MOV WORD PTR CS:HWAIT,NO_DESNOW ;get rid of desnow
- MOV AX,DS:[0484H] ;get number of rows
- DEC AL ;last row is for prompt line
- MOV CS:[ROWS],AL ;save the number of rows
- NOT_EGA:
- MOV AX,DS:[044AH] ;get number of columns
- MOV CS:COLUMNS,AX ;and store it
- MOV AX,DS:[0463H] ;address of display card
- ADD AX,6 ;add six to get status port
- PUSH CS
- POP DS
- ASSUME DS:CSEG
- MOV STATUS_REG,AX
- CMP AX,3BAH ;is this a MONO display?
- JNE COLOR ;if not, must be a CGA
- MOV WORD PTR HWAIT,NO_DESNOW ;get rid of desnow
- JMP SHORT MOVE_STACK
- COLOR:
- MOV VIDEO_SEG,0B800H ;segment for color card
- XOR BH,BH ;use page zero
- MOV AH,8 ;get current attribute
- INT 10H
- AND AH,77H ;turn off blink and high intensity
- MOV NORMAL,AH ;save the normal attribute
- XOR AH,01110111B ;flip the color bits
- MOV INVERSE,AH
- OR AH,80H
- MOV SRCH_CLR,AH ;search is inverse/blink
- MOVE_STACK:
- MOV BX,OFFSET END_BUFFER
- ;**rounding ADD BX,15 ;add offset value for SEG rounding up
- MOV CL,4 ;convert program size to
- SHR BX,CL ; paragraphs
- MOV AH,4AH ;deallocate unused memory
- INT 21H ;DOS call
- MOV BX,1000H ;request 64K for file segment
- MOV AH,48H
- INT 21H ;DOS call
- MOV ES,AX
- ASSUME ES:FILE_SEG
- MOV AH,48H ;request 64K for paste buffer
- INT 21H ;DOS call
- JNC GOT_ENOUGH ;if enough memory, continue
- NOT_ENOUGH:
- MOV DX,OFFSET MEMORY_ERROR
- EXIT_2_DOS: JMP EXIT_TO_DOS ;jump island to allow SHORT jumps.
- ;-----------------------
- GOT_ENOUGH:
- MOV PASTE_SEG,AX ;use this for the paste buffer
- GET_FILENAME:
- MOV SI,80H ;point to command tail in PSP
- MOV CL,[SI] ;get number of characters in tail
- XOR CH,CH ;make it a word
- INC SI ;point to first character
- PUSH SI
- ADD SI,CX ;point to last character
- MOV BYTE PTR [SI],0 ;make it an ASCIIZ string (clear the CR)
- MOV NAME_END,SI ;save pointer to last character
- POP SI ;get back pointer to filename
- JCXZ NO_FILENAME ;if no params, just exit
- CLD
- DEL_SPACES:
- LODSB ;get character into AL
- CMP AL," " ;is it a space?
- JNE FOUND_LETTER
- LOOP DEL_SPACES
- FOUND_LETTER:
- DEC SI ;backup pointer to first letter
- MOV NAME_POINTER,SI ;save pointer to filename
- MOV DX,NAME_POINTER
- MOV AX,4300H ;get file attribute byte (in CL)
- INT 21H ;DOS call
- JC ATTRIB_ERROR
- AND CL,1 ;keep bit-0, read-only status
- ADD CL,CL ;shift RO bit up
- OR INSERT_MODE,CL ;save as index modifier value
- ATTRIB_ERROR:
- MOV DX,SI
- MOV AX,3D00H ;setup to open file
- INT 21H ;DOS call
- ; If no carry, Then the opened file handle is in AX
- ; If no carry, Then the opened file handle is in AX
- JC NO_FILENAME ;if we can't open, must be new file
- FILE_OPENED:
- PUSH ES
- POP DS ;DS has file segment also
- ASSUME DS:FILE_SEG
- MOV BX,AX ;get the handle into BX
- XOR DX,DX ;point to file buffer, DS:DX
- MOV CX,0FFFEH ;read almost 64K bytes
- MOV AH,3FH ;read from file or device
- ; BX = file handle
- INT 21H ;DOS call
- ; If no carry, Then AX contains number of bytes read
- MOV DI,AX ;number of bytes read in
- JNC FILE_READ_OK ;if no error, take jump
- MOV DX,OFFSET READ_ERR_MESS
- ;-----------------------
- ; the file has been opened, it should now be closed. (JEG)
- ;-----------------------
- CLOSE_ERR_EXIT:
- MOV AH,3EH ;close the opened file
- ; BX = file handle
- INT 21H
- JMP SHORT EXIT_2_DOS
- ;-----------------------
- FILE_READ_OK:
- MOV LAST_CHAR,DI ;save the file size
- CMP CX,AX ;did the buffer fill?
- MOV DX,OFFSET FILE_TOO_BIG
- JE CLOSE_ERR_EXIT ;if yes, it is too big
- MOV AH,3EH ;close the file
- ; BX = file handle
- INT 21H
- ;**dirty MOV BYTE PTR CS:DIRTY_FILE,0 ;file opened but not altered.
- NO_FILENAME:
- PUSH ES
- PUSH ES ;save the file segment
- PUSH CS
- POP DS
- ASSUME DS:CSEG
- ;-----------------------
- ;INT 24 is the critical error handler
- ;-----------------------
- MOV AX,3524H ;get INT 24 vector
- INT 21H ;DOS call
- MOV WORD PTR OLDINT24,BX ;store the offset
- MOV WORD PTR OLDINT24+2,ES ;and the segment
- MOV DX,OFFSET NEWINT24 ;point to new vector
- MOV AX,2524H ;now change INT 24 vector
- INT 21H ;DOS call
- ;-----------------------
- ;INT 23 is the CTRL-Break or CTRL-C handler
- ;-----------------------
- MOV DX,OFFSET NEWINT23
- MOV AX,2523H ;set the INT 23 vector
- INT 21H ;DOS call
- POP ES ;get back file segment
- POP DS
- ASSUME DS:FILE_SEG
- CALL REDO_PROMPT ;draw the prompt line
- ;-----------------------------------------------------------------------
- ; Here's the main loop. It updates the screen, then reads a keystroke.
- ;-----------------------------------------------------------------------
- READ_A_KEY:
- CMP MARK_MODE,0 ;is the mark state on?
- JZ MARK_OFF ;if not, skip this
- OR DIRTY_BITS,4 ;refresh the current row
- MOV DX,CURS_POSN
- CMP SAVE_ROW,DH ;are we on the save row?
- JE SAME_ROW ;if yes, then redo the row only
- OR DIRTY_BITS,1 ;refresh the whole screen
- SAME_ROW:
- MOV AX,CURSOR ;get cursor location
- MOV BX,MARK_HOME ;get the anchor mark position
- CMP AX,BX ;moving backward in file?
- JAE SAME1
- MOV MARK_START,AX ;switch start and end positions
- MOV MARK_END,BX
- JMP SHORT MARK_OFF
- SAME1:
- MOV MARK_END,AX ;store start and end marks
- MOV MARK_START,BX
- MARK_OFF:
- CALL DISPLAY_SCREEN ;redraw the screen
- XOR AH,AH ;read the next key (wait if none ready)
- INT 16H ;BIOS call
- ; AL = ASCII code or 0 (for function keys)
- ; AH = scan code
- TEST SRCH_FLG,0FFH
- JZ CHECK_KEY ;jump if inverse not on
- MOV SRCH_FLG,0 ;turn off highlight
- OR DIRTY_BITS,1 ;redraw screen (next time)
- CHECK_KEY:
- OR AL,AL ;is this an extended code?
- JZ IS_EXTENDED_CODE ;(jump if not an ASCII character)
- CALL INSERT_KEY ;put this ASCII character in the file
- ;**short JMP READ_A_KEY ;get another key
- JMP SHORT RD_NEXT_KEY ;get another key
- ;---------------------------------------
- IS_EXTENDED_CODE:
- ;-----------------------
- ; The following code is for "orphan" key codes and alias keys
- ;-----------------------
- CMP AH,132 ;is it Ctrl-PgUp? (an orphan code)
- JNE NOT_CT_PGUP
- CALL CTRL_PGUP
- ;**short JMP READ_A_KEY
- JMP SHORT RD_NEXT_KEY ;get another key
- ;-----------------------
- NOT_CT_PGUP:
- CMP AH,32 ;is it Alt-D (MultiEdit Del-EOL)?
- JNE NOT_ALT_D
- MOV AH,66 ;substitute scan code for F8
- NOT_ALT_D:
- CMP AH,31 ;is it Alt-S (BSE string search)?
- JNE NOT_ALT_S
- MOV AH,64 ;substitute scan code for F6
- NOT_ALT_S:
- CMP AH,30 ;is it Alt-A (BSE search again)?
- JNE NOT_ALT_A
- MOV AH,89 ;substitute scan code for Shft-F6
- NOT_ALT_A:
- ;-----------------------
- ; The following code sets up a PASCAL style CASE statement.
- ;-----------------------
- CMP AH,DISPATCH_END ;split the dispatch table
- JB DO_DISPATCH
- ;-----------------------
- ; offset cursor group of keys to join the regular dispatch table.
- ;-----------------------
- CMP AH,DISP_CURS_BASE
- JB RD_NEXT_KEY
- CMP AH,DISP_CURS_END
- JAE RD_NEXT_KEY
- SUB AH,LOW (DISP_CURS_BASE - DISPATCH_END) ;close table gap
- DO_DISPATCH:
- ;-----------------------
- ; This is a PASCAL style CASE statement.
- ;-----------------------
- MOV BX,AX ;put AH offset value in BX, AL=0
- XCHG BL,BH ;make into a proper word
- SUB BX,DISPATCH_BASE ;zero offset for dispatch table jump
- JC RD_NEXT_KEY ;too low, not in table
- ADD BX,BX ;make into word
- CALL CS:DISPATCH_TABLE[BX] ;call the key procedure
- RD_NEXT_KEY: JMP READ_A_KEY ;then read another key
- ;=======================================================================
- ; KEYBOARD and CURSOR services
- ;=======================================================================
- ; These two routines shift the display right or left to allow editing
- ; files which contain lines longer than 80 columns. Starting with TED2,
- ; they are proper subroutines.
- ;-----------------------------------------------------------------------
- SH_LEFT PROC NEAR
- CMP LEFT_MARGIN,0 ;at start of line already?
- JE NO_SHIFT ;if yes,then don't shift
- SUB LEFT_MARGIN,8 ;move the window over
- JMP SHORT SH_RETURN
- SH_LEFT ENDP
- ;-----------------------------------------------------------------------
- SH_RIGHT PROC NEAR
- CMP LEFT_MARGIN,255 - 8 ;past max allowable margin?
- JAE NO_SHIFT ;then can't move any more
- ADD LEFT_MARGIN,8 ;this moves the margin over
- SH_RETURN:
- CALL CURSOR_COL ;compute column for cursor
- MOV SAVE_COLUMN,DL ;save the current column
- OR DIRTY_BITS,1 ;redraw the screen
- NO_SHIFT:
- ;**dispatch JMP READ_A_KEY
- ;**bad_key RET
- SH_RIGHT ENDP
- ;-----------------------------------------------------------------------
- ; DISPATCH_TABLE calls to BAD_KEY now go here so that the stack can be
- ; kept equallized.
- ;-----------------------------------------------------------------------
- BAD_KEY PROC NEAR
- RET
- BAD_KEY ENDP
- ;=======================================================================
- ; This routine moves the cursor to the top of the file.
- ;-----------------------------------------------------------------------
- TOP PROC NEAR
- XOR AX,AX ;get a zero into AX
- MOV CURSOR,AX ;cursor to start of file
- MOV TOP_OF_SCREEN,AX
- MOV LEFT_MARGIN,AL ;move to far left margin
- MOV CURS_POSN,AX ;home the cursor
- MOV SAVE_COLUMN,AL ;save the cursor column
- MOV DIRTY_BITS,3 ;redraw the screen and cursor
- RET
- TOP ENDP
- ;=======================================================================
- ; This routine moves the cursor to the bottom of the file.
- ;-----------------------------------------------------------------------
- BOTTOM PROC NEAR
- MOV DH,ROWS ;get screen size
- MOV SI,LAST_CHAR ;point to last character
- ;-----------------------
- ; from TEDPLUS
- DEC SI
- ;-----------------------
- MOV LEFT_MARGIN,0 ;set window to start of line
- CALL LOCATE ;adjust the cursor screen position
- CALL HOME ;move cursor to start of line
- MOV DIRTY_BITS,1 ;this will redraw the screen
- RET
- BOTTOM ENDP
- ;=======================================================================
- ; This routine moves the cursor to the start of the current line.
- ; If <HOME> key and already at start of line, move to start of previous line.
- ;-----------------------------------------------------------------------
- HOME_KEY PROC NEAR
- CALL LEFT ;back up one space, in case at home
- HOME_KEY ENDP
- HOME PROC NEAR
- CALL FIND_START ;find start of line
- MOV CURSOR,SI ;save the new cursor
- MOV SAVE_COLUMN,0 ;save the cursor column
- MOV BYTE PTR CURS_POSN,0 ;store the column number
- RET
- HOME ENDP
- ;=======================================================================
- ; These routines move the cursor right and left
- ;-----------------------------------------------------------------------
- RIGHT PROC NEAR
- MOV SI,CURSOR
- CMP SI,LAST_CHAR ;at end of file?
- JE LR_NO_CHANGE ;if yes, then can't move
- ;-----------------------
- ; from TEDPLUS
- INC SI
- CMP SI,LAST_CHAR ;at end of file?
- DEC SI
- JAE INC_RIGHT ;if yes, then increment
- CMP WORD PTR [SI],CRLF ;is it CRLF?
- JE MOVE_DOWN ;if yes, then move down to next line
- INC_RIGHT:
- ;-----------------------
- INC CURSOR ;advance the cursor
- JMP SHORT LR_RETURN
- MOVE_DOWN:
- CALL HOME ;move to start of line
- JMP SHORT DOWN ;and move down one row
- ;(CALL/RETurn)
- RIGHT ENDP
- ;-----------------------------------------------------------------------
- LEFT PROC NEAR
- CMP CURSOR,0 ;at start of file?
- JZ LR_NO_CHANGE ;then can't move left
- MOV DX,CURS_POSN
- OR DL,DL ;at first column?
- JZ MOVE_UP ;if yes, then move up one
- DEC CURSOR ;shift the cursor offset
- LR_RETURN:
- CALL CURSOR_COL ;compute column for cursor
- MOV SAVE_COLUMN,DL ;save the cursor column
- LR_NO_CHANGE:
- MOV UNDO_LENGTH,0
- RET
- ;-----------------------
- MOVE_UP:
- CALL UP ;move up to next row
- JMP SHORT ENDD ;and move to end of line
- ;(CALL/RETurn)
- LEFT ENDP
- ;-----------------------------------------------------------------------
- ; This routine moves the cursor to the end of the current line.
- ; If END key and already at end of line, move to end of next line.
- ;-----------------------------------------------------------------------
- END_KEY PROC NEAR
- CALL RIGHT ;move one space right, if at EOL
- END_KEY ENDP
- ENDD PROC NEAR
- MOV SI,CURSOR
- CALL FIND_EOL ;find end of this line
- MOV CURSOR,SI ;store the new cursor
- CALL CURSOR_COL ;compute the correct column
- MOV SAVE_COLUMN,DL ;save the cursor column
- RET
- ENDD ENDP
- ;-----------------------------------------------------------------------
- ; This routine moves the cursor down one row. When the last row is reached,
- ; the screen is shifted up one row.
- ;-----------------------------------------------------------------------
- DOWN PROC NEAR
- MOV UNDO_LENGTH,0
- MOV DX,CURS_POSN
- CMP DH,ROWS ;at bottom row already?
- MOV SI,CURSOR ;get position in file
- JE SCREEN_UP ;if at bottom, then scroll up
- CALL FIND_NEXT ;find the start of next line
- JC DOWN_RET ;if no more lines, then return
- MOV CURSOR,SI
- INC DH ;advance cursor to next row
- CALL SHIFT_RIGHT ;move cursor to current column
- DOWN_RET:
- RET
- ;-----------------------
- SCREEN_UP:
- CMP SI,LAST_CHAR ;get cursor offset
- JE DOWN_RET
- CALL FIND_START ;find the start of this line
- MOV CURSOR,SI ;this is the new cursor
- CALL FIND_NEXT ;find the offset of next line
- JC SHIFT_RET ;if no more lines, then return
- MOV CURSOR,SI ;this is the new cursor
- MOV SI,TOP_OF_SCREEN ;get the start of the top row
- CALL FIND_NEXT ;and find the next line
- MOV TOP_OF_SCREEN,SI ;store the new top of screen
- JMP SHORT SHIFT_RET
- ;(CALL/RETurn)
- DOWN ENDP
- ;-----------------------------------------------------------------------
- ; This routine moves the cursor up one row. If the cursor is at the first row,
- ; the screen is scrolled down.
- ;-----------------------------------------------------------------------
- UP PROC NEAR
- MOV UNDO_LENGTH,0
- MOV DX,CURS_POSN
- MOV SI,CURSOR
- OR DH,DH ;at top row already?
- JZ SCREEN_DN ;if yes, then scroll down
- DEC DH ;move the cursor up one row
- CALL FIND_CR ;find the beginning of this row
- MOV CURSOR,SI
- CALL FIND_START ;find start of this row
- MOV CURSOR,SI
- CALL SHIFT_RIGHT ;skip over to current column
- AT_TOP:
- RET
- ;-----------------------
- SCREEN_DN:
- MOV SI,TOP_OF_SCREEN
- OR SI,SI ;at start of file?
- JZ AT_TOP ;if at top, then do nothing
- CALL FIND_PREVIOUS ;find the preceding line
- MOV TOP_OF_SCREEN,SI ;save new top of screen
- MOV SI,CURSOR
- CALL FIND_PREVIOUS ;find the preceding line
- MOV CURSOR,SI ;this is the new cursor
- SHIFT_RET:
- OR DIRTY_BITS,1 ;need to redraw the screen
- MOV SI,CURSOR
- MOV DX,CURS_POSN
- JMP SHIFT_RIGHT ;move cursor to current column
- ;(CALL/RETurn)
- UP ENDP
- ;=======================================================================
- ; These four routines move the screen one page at a time by calling the
- ; UP and DOWN procedures.
- ;-----------------------------------------------------------------------
- CTRL_PGDN PROC NEAR ;do PgDn then PgUp
- CALL PGDN
- JMP SHORT PGUP
- ;(CALL/RETurn)
- CTRL_PGDN ENDP
- ;-----------------------------------------------------------------------
- PGUP PROC NEAR
- MOV CS:PAGE_PROC,OFFSET UP
- JMP SHORT PAGE_UP_DN
- PGUP ENDP
- ;-----------------------------------------------------------------------
- CTRL_PGUP PROC NEAR ;do PgUp then PgDn
- CALL PGUP
- ;** JMP SHORT PGDN
- ;(CALL/RETurn)
- CTRL_PGUP ENDP
- ;-----------------------------------------------------------------------
- PGDN PROC NEAR
- MOV CS:PAGE_PROC,OFFSET DOWN
- PAGE_UP_DN:
- MOV CL,CS:ROWS ;get vertical length of screen
- SUB CL,5 ;don't page a full screen
- XOR CH,CH ;make it a word
- PAGE_LOOP:
- PUSH CX
- CALL PAGE_PROC ;move the cursor down
- POP CX
- LOOP PAGE_LOOP ;loop for one page length
- RET
- PGDN ENDP
- ;=======================================================================
- ; This routine toggles the Insert/Overstrike mode.
- ;-----------------------------------------------------------------------
- INSERT PROC NEAR
- ; ASSUME DS:NOTHING
- ;**RO mode NOT CS:INSERT_MODE ;toggle the switch
- XOR CS:INSERT_MODE,1 ;toggle the "I/O" switch
- CALL REDO_PROMPT ;redraw the insert/overstrike status
- RET
- INSERT ENDP
- ;=======================================================================
- ; FILE MANIPULATION services
- ;=======================================================================
- ; This routine forces the insertion of the NUL character, 00H, in the file.
- ;-----------------------------------------------------------------------
- NUL_CHAR PROC NEAR
- XOR AX,AX
- NUL_CHAR ENDP
- ;-----------------------------------------------------------------------
- ; This routine adds a character into the file. In insert mode, remaining
- ; characters are pushed forward. If the scan code for <Enter> is detected,
- ; a <CR><LF> pair is added as the EOL marker. If the scan code for
- ; <Backspace> is detected, the character to the left of the cursor is
- ; deleted (unless the cursor is already at the start of the file).
- ;-----------------------------------------------------------------------
- INSERT_KEY PROC NEAR
- ASSUME DS:FILE_SEG
- MOV SI,CS:CURSOR
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JA FILE_FULL ;jump if read-only file
- CMP AH,28 ;was this the <Enter> key scan code?
- JE NEW_LINE ;if yes, make new line: <CR><LF>.
- CMP AH,14 ;was it the <Backspace> key scan code?
- JE BACK_SPACE ;if yes, delete character left.
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JE INSERT_CHAR ;jump if Insert
- ;-----------------------
- ; test for overstrike character at end of line or file.
- ; if EOL or EOF, then insert rather than overstrike.
- ;-----------------------
- CMP SI,CS:LAST_CHAR ;at end of file?
- JAE INSERT_CHAR
- INC SI
- CMP SI,CS:LAST_CHAR ;at end of file?
- DEC SI
- JAE INSERT_CHAR
- CMP WORD PTR [SI],CRLF ;at end of line?
- JE INSERT_CHAR
- OVERSTRIKE_NOT_AT_CRLF:
- MOV DI,SI
- PUSH AX ;save new character
- XCHG DS:[SI],AL ;switch new character for old one
- CALL SAVE_CHAR ;store the old character
- POP AX ;get back new character
- JMP SHORT ADVANCE
- ;---------------------------------------
- INSERT_CHAR:
- PUSH SI
- PUSH AX ;save the new character
- MOV AX,1
- CALL OPEN_SPACE ;make room for it at SI
- POP AX ;get back the new character
- POP DI
- JC FILE_FULL
- STOSB ;insert character in file buffer, ES:DI
- ADVANCE:
- OR CS:DIRTY_BITS,4 ;current line is dirty
- ;-----------------------
- ; see if we made a CR-LF pair by adding a Ctrl-M with a Ctrl-J
- ;-----------------------
- CALL C_IF_NEW_CRLF ;see if in middle of new CR-LF
- JC FILE_FULL ;jump if new line was done
- ;------------------------
- CMP AL,CR ;was key <Ctrl-M> - CR?
- JNE INS_NOT_CR
- MOV CS:DIRTY_BITS,1 ;redraw the screen (just in case EOL)
- INS_NOT_CR:
- ;-----------------------
- PUSH UNDO_LENGTH
- CALL RIGHT ;move cursor to next letter
- POP UNDO_LENGTH
- FILE_FULL:
- RET
- CR_AT_EOF:
- INC CS:CURSOR
- RET
- ;---------------------------------------
- ; process the <Enter> key, make new line
- ;---------------------------------------
- NEW_LINE:
- PUSH SI
- MOV AX,2
- CALL OPEN_SPACE ;make space for CR and LF
- POP DI ;get back old cursor location
- JC FILE_FULL
- MOV AX,CRLF ;LF*256+CR
- STOSW ;store the CR and LF
- JMP SHORT ADVANCE_NEW_LINE ;repaint the screen
- ;(CALL/RETurn)
- INSERT_KEY ENDP
- ;---------------------------------------
- ; process the <Backspace> key, delete character left of cursor.
- ;---------------------------------------
- BACK_SPACE PROC NEAR
- OR SI,SI ;is cursor at start of file?
- JZ FILE_FULL ;if so, no delete right
- CALL LEFT ;move left one space (flush UnDo buffer)
- ;**follows JMP DEL_CHAR ;and delete the character (into buffer)
- ;(CALL/RETurn)
- BACK_SPACE ENDP
- ;=======================================================================
- ; This routine deletes the character at the cursor by shifting the remaining
- ; characters forward. <Del> key
- ;-----------------------------------------------------------------------
- DEL_CHAR PROC NEAR
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JA NO_DEL ;jump if read-only file
- MOV CX,LAST_CHAR
- MOV SI,CURSOR
- MOV DI,SI
- CMP SI,CX ;are we at end of file?
- JAE NO_DEL ;if yes, then don't delete
- LODSB ;loads char in AL, DS:SI
- CALL SAVE_CHAR ;save it for UNDO function
- MOV AH,[SI] ;look at the next character also
- PUSH AX ;save character we're deleting
- DEC LAST_CHAR ;shorten the file by one
- SUB CX,SI
- REP MOVSB ;move file down one, DS:SI to ES:DI
- POP AX ;get back character we deleted
- CMP AX,CRLF ;did we delete a CR?
- JE COMBINE
- OR DIRTY_BITS,4 ;current line is dirty
- ;-----------------------
- ; see if we made a CRLF by deleting a character.
- ; if we are in the middle of a CRLF, move the cursor back one.
- ;-----------------------
- JMP SHORT C_IF_NEW_CRLF
- ;(CALL/RETurn) - saves a byte
- ;---------------------------------------
- COMBINE: ;deleted an EOL marker, CR-LF
- CALL DEL_CHAR ;now delete the line feed (recursive)
- MOV DIRTY_BITS,3
- MOV DX,CURS_POSN
- MOV SAVE_COLUMN,DL ;save the cursor column
- NO_DEL:
- RET
- DEL_CHAR ENDP
- ;=======================================================================
- ; see if we made a CR-LF pair with the cursor located on the LF character
- ; by joining the character (Ctrl-M) with a (Ctrl-J). If so, back up the
- ; cursor and open a new line and return with carry set. if not, return with
- ; carry clear.
- ;-----------------------------------------------------------------------
- C_IF_NEW_CRLF PROC NEAR
- MOV SI,CS:CURSOR ;present cursor location
- OR SI,SI ;is it at start of file
- JZ DONE_CRLF
- CMP WORD PTR [SI-1],CRLF ;did we make CR-LF?
- JNE DONE_CRLF
- DEC CS:CURSOR ;move cursor back to point at CR code
- C_IF_NEW_CRLF ENDP
- ;---------------------------------------
- ; This routine opens a new line.
- ;---------------------------------------
- ADVANCE_NEW_LINE PROC NEAR ;split line on screen for CR-LF
- CALL HOME ;cursor to start of line
- CALL DOWN ;move down to the new line
- MOV DIRTY_BITS,3 ;repaint the screen and cursor
- STC ;C=1 if new line was done
- RET
- DONE_CRLF:
- CLC ;C=0 if not new line
- RET
- ADVANCE_NEW_LINE ENDP
- ;=======================================================================
- ; This routine restores any characters which have recently been deleted.
- ;-----------------------------------------------------------------------
- UNDO PROC NEAR
- ; ASSUME DS:FILE_SEG
- XOR AX,AX
- XCHG AX,CS:UNDO_LENGTH ;get buffer length
- MOV SI,OFFSET UNDO_BUFFER
- JMP INSERT_STRING
- ;(CALL/RETurn)
- UNDO ENDP
- ;=======================================================================
- ; This routine inserts spaces into the file buffer. On entry, AX
- ; contains the number of spaces to be inserted. On return, CF=1 if
- ; there was not enough space in the file buffer.
- ;-----------------------------------------------------------------------
- OPEN_SPACE PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV CX,LAST_CHAR ;last character in the file
- MOV SI,CX
- MOV DI,CX
- ADD DI,AX ;offset for new end of file
- JC NO_ROOM ;if no more room, return error
- MOV LAST_CHAR,DI ;save offset of end of file
- SUB CX,CURSOR ;number of characters to shift
- DEC DI
- DEC SI
- STD ;string moves goes forward
- REP MOVSB ;shift the file upward
- CLD
- MOV BYTE PTR DIRTY_FILE,0FFH ;file has been altered
- CLC
- NO_ROOM: ;carry is set if no room in file
- RET
- OPEN_SPACE ENDP
- ;=======================================================================
- ; This routine adds a character to the UNDO buffer.
- ;-----------------------------------------------------------------------
- SAVE_CHAR PROC NEAR
- MOV BX,UNDO_LENGTH
- OR BH,BH ;is buffer filled?
- JNZ NO_SAVE ;buffer overflowed, no insert
- INC UNDO_LENGTH
- MOV BYTE PTR CS:UNDO_BUFFER[BX],AL
- MOV BYTE PTR CS:DIRTY_FILE,0FFH ;file altered
- NO_SAVE:
- RET
- SAVE_CHAR ENDP
- ;=======================================================================
- ; This routine deletes from the cursor position to the end of the line.
- ;-----------------------------------------------------------------------
- DEL_EOL PROC NEAR
- ;-----------------------
- ; from TEDPLUS, modified by JEG, delete line if at column 1.
- ;**Shft-F8 MOV CX,CURSOR_POSN
- ;**Shft-F8 JCXZ DEL_L
- ;-----------------------
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JA NO_DEL_L ;jump if read-only file
- MOV LINE_FLAG,0
- PUSH CURSOR ;save starting cursor location
- CALL ENDD ;move to the end of the line
- POP SI ;get back starting cursor
- MOV CX,CURSOR ;offset of end of line
- MOV CURSOR,SI ;restore starting cursor
- JMP SHORT DEL_END ;delete characters to end of line
- ;(CALL/RETurn)
- DEL_EOL ENDP
- ;-----------------------------------------------------------------------
- ; This routine deletes a line, placing it in the line buffer. <F9>, <Shft-F8>
- ;-----------------------------------------------------------------------
- DEL_L PROC NEAR
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JA NO_DEL_L ;jump if read-only file
- MOV LINE_FLAG,1
- CALL FIND_START ;find start of this line
- MOV CURSOR,SI ;this will be the new cursor
- PUSH SI ;save the cursor position
- CALL FIND_NEXT ;find the next line
- MOV CX,SI ;CX will hold line length
- POP SI ;get back new cursor location
- DEL_END:
- MOV BYTE PTR DIRTY_FILE,0FFH ;file has been altered
- SUB CX,SI ;number of bytes on line
- OR CH,CH ;is line too long to fit?
- JZ NOT_TOO_LONG
- MOV CX,100H ;save only 256 characters
- NOT_TOO_LONG:
- MOV LINE_LENGTH,CX ;store length of deleted line
- JCXZ NO_DEL_L
- MOV DI,OFFSET LINE_BUFFER ;buffer for deleted line
- PUSH CX
- PUSH ES
- PUSH CS
- POP ES ;line buffer is in CSEG
- REP MOVSB ;put deleted line in buffer
- POP ES ;get back file segment
- POP AX
- MOV CX,LAST_CHAR ;get the file size
- SUB LAST_CHAR,AX ;subtract the deleted line
- MOV SI,CURSOR ;get new cursor location
- MOV DI,SI
- ADD SI,AX ;SI points to end of file
- SUB CX,SI ;length of remaining file
- JCXZ NO_DEL_L
- REP MOVSB ;shift remainder of file up
- NO_DEL_L:
- MOV DIRTY_BITS,3 ;redraw the screen and adjust cursor
- RET
- DEL_L ENDP
- ;=======================================================================
- ; This routine undeletes a line by copying it from the line buffer into
- ; the file.
- ;-----------------------------------------------------------------------
- UDEL_L PROC NEAR
- CMP LINE_FLAG,0 ;is this an end of line only?
- JE UDEL_EOL ;if yes, don't home the cursor
- CALL HOME ;move cursor to home
- UDEL_EOL:
- MOV AX,LINE_LENGTH ;length of deleted line
- MOV SI,OFFSET LINE_BUFFER
- ;**insert_str JMP INSERT_STRING ;(follows immediately)
- ;(CALL/RETurn)
- UDEL_L ENDP
- ;-----------------------------------------------------------------------
- ; This routine inserts AX characters from CS:SI into the file.
- ; (This routine follows "UDEL_L")
- ;-----------------------------------------------------------------------
- INSERT_STRING PROC NEAR
- ; ASSUME DS:FILE_SEG
- PUSH SI ;save string buffer
- MOV SI,CS:CURSOR ;get cursor offset
- PUSH AX ;save length of string
- PUSH SI
- CALL OPEN_SPACE ;make space to insert string
- POP DI ;get back cursor position
- POP CX ;get back string length
- POP SI ;get back string buffer
- JC NO_SPACE ;if no space available, exit
- PUSH DS
- PUSH CS
- POP DS
- ASSUME DS:CSEG
- REP MOVSB ;copy characters DS:SI to ES:DI
- MOV DIRTY_BITS,3 ;redraw the screen and adjust cursor
- POP DS
- ASSUME DS:NOTHING
- CALL C_IF_NEW_CRLF
- NO_SPACE:
- RET
- INSERT_STRING ENDP
- ;=======================================================================
- ; VIDEO services
- ;=======================================================================
- ; This routine displays a character by writing directly to
- ; the screen buffer. To avoid screen noise (snow) on the color
- ; card (CGA), the horizontal retrace has to be monitored.
- ;-----------------------------------------------------------------------
- WRITE_INVERSE PROC NEAR
- ASSUME DS:FILE_SEG, ES:FILE_SEG
- MOV BH,CS:INVERSE ;attribute for inverse video
- JMP SHORT WRITE_SCREEN
- ;-----------------------------------------------------------------------
- WRITE_FIND:
- MOV BH,CS:SRCH_CLR ;attribute for find string
- ; MOV BH,CS:INVERSE ;attribute for find string
- JMP SHORT WRITE_SCREEN
- ;-----------------------------------------------------------------------
- WRITE_NORMAL:
- MOV BH,CS:NORMAL ;attribute for normal video
- WRITE_SCREEN:
- MOV BL,AL ;save the character
- PUSH ES
- LES DX,CS:VIDEO_STATUS_REG ;video status register
- ;-------------------------------------------------------
- ; HWAIT is used to "desnow" the display for the CGA.
- ; If not CGA, the following instruction is modified to a
- ; JMP SHORT WRITE_IT
- ;-------------------------------------------------------
- HWAIT:
- IN AL,DX ;get video status
- ROR AL,1 ;look at horizontal retrace
- JNC HWAIT ;wait for retrace
- WRITE_IT:
- MOV AX,BX ;get the character/attributes
- STOSW ;write the character
- POP ES
- RET
- WRITE_INVERSE ENDP
- ;=======================================================================
- ; This routine moves the cursor to the row/column in DX.
- ;-----------------------------------------------------------------------
- SET_CURSOR PROC NEAR
- XOR BH,BH ;we're using page zero
- MOV AH,2 ;BIOS set cursor function
- INT 10H
- RET
- SET_CURSOR ENDP
- ;=======================================================================
- ; This routine computes the video buffer offset for the row/column in DX.
- ;-----------------------------------------------------------------------
- POSITION PROC NEAR
- MOV AX,CS:COLUMNS ;take columns per row
- MUL DH ;times row number
- XOR DH,DH
- ADD AX,DX ;add the column number
- SHL AX,1 ;times 2 for offset
- MOV DI,AX ;return result in DI
- RET
- POSITION ENDP
- ;=======================================================================
- ; This routine erases from the location in DX to the right edge of the screen.
- ;-----------------------------------------------------------------------
- ERASE_EOL PROC NEAR
- ASSUME DS:NOTHING
- CALL POSITION ;find screen offset
- MOV CX,CS:COLUMNS ;get screen size
- SUB CL,DL ;subtract current position
- JCXZ NO_CLEAR
- ERASE_LOOP:
- MOV AL," " ;write blanks to erase
- CALL WRITE_NORMAL ;display it
- LOOP ERASE_LOOP
- NO_CLEAR:
- RET
- ERASE_EOL ENDP
- ;=======================================================================
- ; This routine displays the function key prompt and insert/overstrike mode
- ; state. It sets DIRTY_BITS := 3 to force redraw of the entire screen
- ; and locate cursor.
- ;-----------------------------------------------------------------------
- REDO_PROMPT PROC NEAR
- ASSUME DS:NOTHING, ES:NOTHING
- PUSH DS
- PUSH CS
- POP DS
- ASSUME DS:CSEG
- MOV DH,ROWS ;put prompt at last row
- INC DH
- XOR DL,DL ;and column 0
- CALL POSITION ;convert to screen offset
- MOV SI,OFFSET PROMPT_STRING
- KEY_LOOP:
- MOV AL,"F" ;display an "F"
- CALL WRITE_NORMAL
- LODSB
- OR AL,AL ;last key in prompt?
- JZ PROMPT_DONE
- CALL WRITE_NORMAL
- CMP BYTE PTR CS:[SI],"0" ;is it F10?
- JNE TEXT_LOOP
- LODSB
- CALL WRITE_NORMAL
- TEXT_LOOP:
- LODSB
- OR AL,AL ;last letter in word?
- JNZ WRITE_CHAR
- MOV AL," " ;display a space
- CALL WRITE_NORMAL
- JMP KEY_LOOP
- WRITE_CHAR:
- CALL WRITE_INVERSE ;display the letter
- JMP TEXT_LOOP ;do the next letter
- PROMPT_DONE:
- MOV DH,ROWS
- INC DH ;get the last row on the screen
- MOV DL,PROMPT_LENGTH + 9
- CALL ERASE_EOL ;erase to the end of this row
- MOV BL,INSERT_MODE
- XOR BH,BH
- MOV AL,CS:[BX + OFFSET INSERT_CODE]
- ; MOV AL,"O" ;write an "O" (for "Overstrike")
- ; CMP INSERT_MODE,1 ;in insert mode?
- ; JB OVERSTRIKE
- ; MOV AL,"I" ;write an "I" (for "Insert")
- ; JE OVERSTRIKE
- ; MOV AL,"R" ;write an "R" (for "read-only")
- OVERSTRIKE:
- DEC DI ;backup one character position
- DEC DI
- CALL WRITE_NORMAL
- MOV DIRTY_BITS,3 ;now redraw the entire screen
- POP DS
- ASSUME DS:NOTHING
- RET
- REDO_PROMPT ENDP
- ;=======================================================================
- ; This routine displays the file buffer on the screen.
- ; DISPLAY_BOTTOM has been deleted to reduce the program code size.
- ;-----------------------------------------------------------------------
- DISPLAY_SCREEN PROC NEAR
- ASSUME DS:FILE_SEG, ES:FILE_SEG
- TEST DIRTY_BITS,2 ;see if we should adjust the cursor
- JZ DISP_CURS_OK
- MOV SI,CURSOR ;get the new cursor offset
- MOV DX,CURS_POSN ;also get the current row
- CALL LOCATE ;adjust the cursor screen position
- DISP_CURS_OK:
- MOV DX,CURS_POSN
- MOV SAVE_ROW,DH
- CALL SET_CURSOR ;position the cursor
- TEST DIRTY_BITS,1 ;see if we should update the screen
- JNZ DO_UPDATE_SCREEN
- TEST DIRTY_BITS,4 ;is the current line dirty?
- JZ DISP_DONE ;if not, take jump
- CALL DISPLAY_CURRENT ;redraw the current line
- JMP SHORT DISP_DONE
- DO_UPDATE_SCREEN:
- MOV SI,TOP_OF_SCREEN ;point to first char on screen
- XOR DH,DH ;start at first row
- ; JMP SHORT NEXT_ROW
- ; ;-----------------------
- ;DISPLAY_BOTTOM: ;this redraws the bottom only
- ; CALL FIND_START ;find first character on this row
- ; MOV DX,CURS_POSN ;get current cursor row
- NEXT_ROW:
- PUSH DX
- CALL DISPLAY_LINE ;display a line
- POP DX
- ;-----------------------
- ; the keyboard is tested here to see if a key is waiting
- ;-----------------------
- MOV AH,1
- INT 16H
- MOV AL,1 ;for dirty_bits, update not completed
- JNZ DISP_NOT_DONE ;jump if there is a key is waiting
- INC DH ;move to the next row
- CMP DH,ROWS ;at end of screen yet?
- JBE NEXT_ROW ;do all the rows
- DISP_DONE:
- MOV AL,0
- DISP_NOT_DONE:
- MOV DIRTY_BITS,AL ;screen is completely redone
- RET
- DISPLAY_SCREEN ENDP
- ;=======================================================================
- ; This routine displays a single line to the screen. DH holds the
- ; row number, SI has the offset into the file buffer. Tabs are expanded.
- ; Adjustment is made for side shift.
- ;-----------------------------------------------------------------------
- DISPLAY_CURRENT PROC NEAR
- ; ASSUME DS:FILE_SEG
- CALL FIND_START
- MOV DX,CS:CURS_POSN
- DISPLAY_CURRENT ENDP
- ;-----------------------
- DISPLAY_LINE PROC NEAR ;external entry point
- XOR DL,DL ;start at column zero
- MOV CS:MARGIN_COUNT,DL
- MOV CX,DX ;use CL to count the columns
- CALL POSITION ;compute offset into video
- NEXT_CHAR:
- CMP SI,LAST_CHAR ;at end of file?
- JAE LINE_DONE
- LODSB ;get next character, DS:SI
- CMP AL,TAB ;is this a Tab character?
- JE EXPAND_TAB ;if yes, expand to spaces
- CMP SI,LAST_CHAR ;at end of file now?
- JAE DO_PUT ;jump, can't be CR-LF pair
- CMP WORD PTR [SI-1],CRLF ;EOL marker
- JE FOUND_CR ;quit when a CR-LF is found
- DO_PUT:
- CALL PUT_CHAR ;put character onto screen
- TAB_DONE:
- CMP CL,CS:COLUMNSB ;at right edge of screen?
- JB NEXT_CHAR
- ;-----------------------
- ; from TEDPLUS
- INC SI
- CMP SI,LAST_CHAR ;at end of file?
- DEC SI
- JAE NOT_BEYOND
- CMP WORD PTR [SI],CRLF ;at end of line?
- ;----------------------
- JE NOT_BEYOND
- DO_DIAMOND:
- DEC DI ;backup one character
- DEC DI
- MOV AL,4 ;show a diamond
- CALL WRITE_INVERSE ;in inverse video
- NOT_BEYOND:
- JMP FIND_NEXT ;find start of next line
- ;(CALL/RETurn)
- ;---------------------------------------
- EXPAND_TAB:
- MOV AL," " ;convert tab to spaces
- CALL PUT_CHAR
- MOV AL,MARGIN_COUNT
- ADD AL,CL ;CL is column count
- TEST AL,00000111B ;at even multiples of eight?
- JNZ EXPAND_TAB ;if not, keep adding spaces
- JMP TAB_DONE
- ;---------------------------------------
- FOUND_CR:
- INC SI ;past the CR-LF
- LINE_DONE:
- MOV DX,CX
- JMP ERASE_EOL ;erase the end of the line
- ;(CALL/RETurn)
- ;-----------------------
- DISPLAY_LINE ENDP
- ;=======================================================================
- ; This routine displays a single character to the screen. If the character
- ; is marked, it is shown in inverse video. Characters outside the current
- ; margin are not displayed. Characters left of the margin are skipped.
- ;-----------------------------------------------------------------------
- PUT_CHAR PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV BL,MARGIN_COUNT ;get distance to left margin
- CMP BL,LEFT_MARGIN ;are we inside left margin?
- JAE IN_WINDOW ;yes, show the character
- INC BL
- MOV MARGIN_COUNT,BL
- RET
- ;-----------------------
- ; from TEDPLUS
- IN_WINDOW:
- CMP SRCH_FLG,0
- JE CKM
- CMP SI,SRCH_BASE
- JBE CKM
- CMP SI,SRCH_END
- JA CKM
- CALL WRITE_FIND
- ;**inverse CALL WRITE_INVERSE ;found string highlighted, inverse video
- JMP SHORT NEXT_COL
- CKM:
- ;-----------------------
- CMP SI,MARK_START ;is this character marked?
- JBE NOT_MARKED
- CMP SI,MARK_END
- JA NOT_MARKED
- CALL WRITE_INVERSE ;marked characters shown inverse
- JMP SHORT NEXT_COL
- ;-----------------------
- NOT_MARKED:
- CALL WRITE_NORMAL
- NEXT_COL:
- INC CL ;increment the column count
- RET
- PUT_CHAR ENDP
- ;=======================================================================
- ; This routine adjusts the cursor position ahead to the saved cursor column.
- ; On entry DH has the cursor row.
- ;-----------------------------------------------------------------------
- SHIFT_RIGHT PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV CL,SAVE_COLUMN ;keep the saved cursor offset
- XOR CH,CH
- MOV BP,CX ;keep the saved cursor position
- ADD CL,LEFT_MARGIN ;shift into visible window
- ADC CH,0
- XOR DL,DL
- MOV CURS_POSN,DX ;get cursor row/column
- JCXZ NO_CHANGE
- RIGHT_AGAIN:
- PUSH CX
- ;-----------------------
- ; (JEG)
- INC SI
- CMP SI,LAST_CHAR ;at end of file?
- DEC SI
- JAE DO_MOVE
- CMP WORD PTR [SI],CRLF ;at end of line?
- ;-----------------------
- JE DONT_MOVE ;if at end, stop moving
- DO_MOVE:
- CALL RIGHT ;move right one character
- DONT_MOVE:
- POP CX
- MOV AL,SAVE_COLUMN
- XOR AH,AH
- CMP AX,CX ;is cursor still in margin?
- JL IN_MARGIN ;if yes, keep moving
- MOV DX,CURS_POSN ;get cursor column again
- XOR DH,DH
- CMP DX,BP ;at saved cursor position?
- JE RIGHT_DONE ;if yes, we're done
- JA RIGHT_TOO_FAR ;did we go too far?
- IN_MARGIN:
- LOOP RIGHT_AGAIN
- RIGHT_DONE:
- MOV CX,BP
- MOV SAVE_COLUMN,CL ;get back saved cursor position
- NO_CHANGE:
- RET
- ;-----------------------
- RIGHT_TOO_FAR:
- CALL LEFT ;move back left one place
- MOV CX,BP
- MOV SAVE_COLUMN,CL ;get back saved cursor position
- RET
- SHIFT_RIGHT ENDP
- ;=======================================================================
- ; This routine finds the beginning of the previous line.
- ;-----------------------------------------------------------------------
- FIND_PREVIOUS PROC NEAR
- ; ASSUME DS:FILE_SEG
- PUSH CURSOR ;save the cursor location
- CALL FIND_CR ;find the start of this line
- MOV CURSOR,SI ;save the new cursor
- CALL FIND_START ;find the start of this line
- POP CURSOR ;get back starting cursor
- RET
- FIND_PREVIOUS ENDP
- ;=======================================================================
- ; This routine searches for the previous carriage return.
- ; Search starts at DS:SI.
- ;-----------------------------------------------------------------------
- FIND_CR PROC NEAR
- ; ASSUME DS:FILE_SEG
- PUSH CX
- MOV AL,LF ;look for a line feed character
- MOV DI,SI
- MOV CX,SI
- JCXZ AT_BEGINNING
- DEC DI
- STD ;search backwards
- LF_PREV:
- REPNE SCASB ;scan for the character
- ;-----------------------
- ; from TEDPLUS
- JCXZ LF_END
- CMP BYTE PTR [DI],CR
- JNE LF_PREV
- DEC DI
- LF_END:
- ;-----------------------
- CLD ;restore the direction flag
- INC DI
- MOV SI,DI
- AT_BEGINNING:
- POP CX
- RET
- FIND_CR ENDP
- ;=======================================================================
- ; This routine skips past the CR and LF at SI. SI returns new offset.
- ;-----------------------------------------------------------------------
- SKIP_CR_LF PROC NEAR
- ; ASSUME CS:FILE_SEG
- CMP SI,LAST_CHAR ;at last char in file?
- JAE NO_SKIP ;if yes, don't skip anything
- CMP BYTE PTR [SI],CR ;is first character a CR?
- JNE NO_SKIP
- INC SI ;look at next character
- CMP SI,LAST_CHAR ;is it at the end of file?
- JAE NO_SKIP ;if yes, don't skip anymore
- CMP BYTE PTR [SI],LF ;is next character a line feed?
- JNE NO_SKIP ;skip any line feeds also
- INC SI
- NO_SKIP:
- RET
- SKIP_CR_LF ENDP
- ;=======================================================================
- ; This routine computes the location of the start of current line.
- ; Returns SI pointing to the first character of the current line.
- ;-----------------------------------------------------------------------
- FIND_START PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV SI,CURSOR ;get the current cursor
- OR SI,SI ;at start of file?
- JZ AT_START ;if yse, we're done
- CALL FIND_CR ;find the CR
- CALL SKIP_CR_LF
- AT_START:
- RET
- FIND_START ENDP
- ;=======================================================================
- ; This routine finds the offset of the start of the next line. The search
- ; is started at location of ES:SI. On return, CF=1 if no CR was found.
- ;-----------------------------------------------------------------------
- FIND_NEXT PROC NEAR
- ; ASSUME DS:FILE_SEG
- PUSH CX
- CALL FIND_EOL ;find the end of this line
- JC AT_NEXT ;if at end of file, return
- CALL SKIP_CR_LF ;skip past CR and LF
- CLC ;indicate end of line found
- AT_NEXT:
- POP CX
- RET
- FIND_NEXT ENDP
- ;=======================================================================
- ; This routine searches for the next carriage return in the file.
- ; The search starts at the offset in register SI.
- ;-----------------------------------------------------------------------
- FIND_EOL PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV AL,CR ;look for a carriage return
- CR_SCAN:
- MOV CX,LAST_CHAR ;last letter in the file
- SUB CX,SI ;count for the search
- MOV DI,SI
- JCXZ AT_END ;if nothing to search, return
- REPNE SCASB ;scan for the character
- MOV SI,DI ;return the location of the CR
- JCXZ AT_END ;if not found, return
- ;-----------------------
- ; from TEDPLUS
- CMP BYTE PTR [SI],LF
- JNE CR_SCAN
- ;-----------------------
- DEC SI ;back up one, to CR character
- CLC ;indicate the CR was found
- RET
- AT_END:
- STC ;indicate CR was not found
- RET
- FIND_EOL ENDP
- ;=======================================================================
- ; This routine positions the screen with the cursor at the row
- ; selected in register DH. On entry, SI holds the cursor offset.
- ;-----------------------------------------------------------------------
- LOCATE PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV CL,DH
- XOR CH,CH
- MOV CURSOR,SI
- XOR DX,DX ;start at top of screen
- OR SI,SI ;at start of buffer?
- JZ LOCATE_FIRST
- CALL FIND_START ;get start of this row
- XOR DX,DX ;start at top of screen
- OR SI,SI ;is cursor at top of file?
- JZ LOCATE_FIRST
- JCXZ LOCATE_FIRST ;if location to top row were done
- FIND_TOP:
- PUSH SI
- PUSH CX
- CALL FIND_CR ;find previous row
- POP CX
- POP AX
- CMP WORD PTR [SI],CRLF
- JNE LOCATE_FIRST
- CMP SI,AX ;did it change?
- JE LOCATE_DONE ;if not, quit moving
- INC DH ;cursor moves to next row
- LOOP FIND_TOP
- LOCATE_DONE:
- PUSH CURSOR
- MOV CURSOR,SI
- CALL FIND_START ;find start at top of screen
- POP CURSOR
- LOCATE_FIRST:
- MOV TOP_OF_SCREEN,SI
- MOV CURS_POSN,DX
- CALL CURSOR_COL
- MOV SAVE_COLUMN,DL
- RET
- LOCATE ENDP
- ;=======================================================================
- ; This routine computes the correct column for the cursor. No inputs.
- ; On exit, CURS_POSN is set and DX has row/column.
- ;-----------------------------------------------------------------------
- CURSOR_COL PROC NEAR
- ; ASSUME DS:FILE_SEG
- MOV SI,CURSOR ;get cursor offset
- CALL FIND_START ;find start of this line
- MOV CX,CURSOR ;cursor location in file
- SUB CX,SI
- MOV DX,CURS_POSN ;get current row
- XOR DL,DL ;start at column zero
- MOV MARGIN_COUNT,DL ;count past the left margin
- JCXZ COL_DONE
- CURSOR_LOOP:
- LODSB ;get the next character
- INC SI
- CMP SI,LAST_CHAR
- DEC SI
- JAE NOT_EOL ;is <CR> without <LF>, at end of file
- CMP WORD PTR [SI-1],CRLF ;(JEG)
- JE COL_DONE ;if at end, we're done
- NOT_EOL:
- CMP AL,TAB ;is it a tab?
- JNE NOT_A_TAB
- MOV BL,MARGIN_COUNT
- OR BL,00000111B
- MOV MARGIN_COUNT,BL
- CMP BL,LEFT_MARGIN ;inside visible window yet?
- JB NOT_A_TAB ;if not, don't advance cursor
- OR DL,00000111B ;move to multiple of eight
- NOT_A_TAB:
- MOV BL,MARGIN_COUNT
- INC BL
- MOV MARGIN_COUNT,BL
- CMP BL,LEFT_MARGIN
- JBE OUT_OF_WINDOW
- INC DL ;we're at next column now
- OUT_OF_WINDOW:
- LOOP CURSOR_LOOP
- COL_DONE:
- CMP DL,COLUMNSB ;past end of display?
- JB COLUMN_OK ;if not, we're OK
- MOV DL,COLUMNSB
- DEC DL ;leave cursor at last column
- COLUMN_OK:
- MOV CURS_POSN,DX ;store at last column
- RET
- CURSOR_COL ENDP
- ;=======================================================================
- ; MARK, CUT, PASTE, PRINT services
- ;=======================================================================
- ; This routine toggles the mark state and resets the paste buffer pointers.
- ;-----------------------------------------------------------------------
- MARK PROC NEAR
- XOR AX,AX
- NOT CS:MARK_MODE ;toggle the mode flag
- CMP CS:MARK_MODE,AL ;turning mode ON?
- JNE MARK_ON
- OR CS:DIRTY_BITS,1 ;need to redraw the screen
- MOV CS:MARK_START,0FFFFH
- JMP SHORT MARK_RET
- ;-----------------------
- MARK_ON:
- MOV AX,CS:CURSOR ;get the cursor offset
- MOV CS:MARK_START,AX ;start of marked range
- MARK_RET:
- MOV CS:MARK_END,AX ;end of marked range
- MOV CS:MARK_HOME,AX ;center of marked range
- RET
- MARK ENDP
- ;=======================================================================
- ; This routine removes the marked text and places it in the paste buffer.
- ;-----------------------------------------------------------------------
- CUT PROC NEAR
- CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
- JA NO_MARK ;jump if read-only file
- CMP CS:MARK_MODE,0 ;is the mark mode on?
- JE NO_MARK ;if not, then do nothing
- MOV CX,CS:MARK_END ;get end of mark region
- MOV SI,CS:MARK_START ;get start of mark region
- SUB CX,SI ;number of bytes selected
- MOV PASTE_SIZE,CX
- XOR DI,DI ;point to paste buffer
- PUSH CX
- PUSH ES
- MOV ES,CS:PASTE_SEG ;set the paste buffer segment to ES
- REP MOVSB ;deleted text to buffer, DS:SI to ES:DI
- POP ES
- POP AX
- MOV CX,CS:LAST_CHAR
- SUB CS:LAST_CHAR,AX ;shorten the file this much
- MOV DI,CS:MARK_START
- MOV SI,CS:MARK_END
- SUB CX,SI
- JCXZ NO_DELETE
- REP MOVSB ;shorten the file, DS:SI to ES:DI
- NO_DELETE:
- MOV DX,CS:CURS_POSN
- MOV SI,CS:MARK_START
- CALL LOCATE ;adjust the screen position
- CALL MARK ;this turns off select
- ;-----------------------
- ; see if we made a CR-LF pair by cutting the character(s) from
- ; between a Ctrl-M and a Ctrl-J. If so, open a new line.
- ;-----------------------
- CALL C_IF_NEW_CRLF
- NO_MARK:
- RET
- CUT ENDP
- ;=======================================================================
- ; This routine copies the paste buffer into the file at the cursor location.
- ;-----------------------------------------------------------------------
- PASTE PROC NEAR
- MOV AX,PASTE_SIZE ;number of characters in buffer
- OR AX,AX ;any there?
- JZ NO_PASTE ;if not, nothing to paste
- MOV SI,CURSOR ;get cursor location
- PUSH AX
- PUSH SI
- CALL OPEN_SPACE ;make room for new characters
- POP DI
- POP CX
- JC NO_PASTE ;if no room, just exit
- XOR SI,SI ;point to start of paste buffer
- PUSH DS
- MOV DS,PASTE_SEG ;segment of paste buffer
- REP MOVSB ;copy in the new characters
- POP DS
- OR DIRTY_BITS,1 ;redraw the screen
- CALL C_IF_NEW_CRLF
- NO_PASTE:
- RET
- PASTE ENDP
- ;=======================================================================
- ; This routine prints an ASCII Form-Feed character.
- ;-----------------------------------------------------------------------
- PRINT_FF PROC NEAR
- CALL MARK ;toggle MARK "on"
- PUSH DS
- PUSH CS
- POP DS
- MOV CX,1 ;one character to print
- MOV SI,OFFSET FF ;offset of last byte in paste buffer
- CALL DO_FF_CHAR
- POP DS
- RET
- FF DB 12 ;the ASCII Form-Feed character
- PRINT_FF ENDP
- ;-----------------------------------------------------------------------
- ; This routine prints the marked text. If printer fails, it is cancelled.
- ;-----------------------------------------------------------------------
- PRINT PROC NEAR
- CMP MARK_MODE,0 ;is mark mode on?
- JE PRINT_RET ;if not, nothing to print
- MOV CX,MARK_END ;end of marked region
- MOV SI,MARK_START ;start of marked region
- SUB CX,SI ;number of bytes selected
- JCXZ PRINT_DONE ;if nothing to print, return
- DO_FF_CHAR:
- XOR DX,DX ;select printer 0
- MOV AH,2
- INT 17H ;get printer status
- TEST AH,10000000B ;is busy bit set?
- JZ PRINT_DONE
- TEST AH,00100000B ;is printer out of paper?
- JNZ PRINT_DONE
- PRINT_LOOP:
- LODSB
- XOR AH,AH
- INT 17H ;print the character
- ROR AH,1 ;check the time out bit
- JC PRINT_DONE ;if set, quit printing
- LOOP PRINT_LOOP
- MOV AL,CR
- ;------ [typographical error in article]
- ;**nop! XOR AH,0 ;[would be No-Operation]
- XOR AH,AH
- ;------
- INT 17H ;finish with a CR
- PRINT_DONE:
- CALL MARK ;turn off the mark status
- PRINT_RET:
- RET
- PRINT ENDP
- ;=======================================================================
- ; CHARACTER STRING SEARCH and SEARCH AGAIN services; HELP screen
- ;=======================================================================
- ; from TEDPLUS
- ; This routine is used to search or search again for a character string.
- ;-----------------------------------------------------------------------
- FIND_STR PROC NEAR
- PUSH DS
- MOV BX,CS
- MOV DS,BX
- ASSUME DS:CSEG
- ;---------------------------------------
- ;** now ShftF6 CMP AH,66H ;Is it shift F9
- CMP AH,89 ;Is it shift-F6 (JEG)
- ;---------------------------------------
- JE RPT_FIND
- MOV DH,ROWS
- INC DH ;Last row on the screen
- XOR DL,DL ;First column
- MOV SI,OFFSET SRCH_PROMPT
- CALL TTY_STRING ;Display search prompt
- MOV DX, OFFSET SRCH_MAX
- MOV AH,0AH
- INT 21H ;Read input string
- RPT_FIND:
- XOR DX,DX
- MOV DL,BYTE PTR SRCH_SIZ
- ADD DX,OFFSET SRCH_STR
- MOV DI,DX
- DEC DI
- MOV SRCH_END,DI
- XOR DX,DX
- MOV SI,CURSOR
- INC SI
- MOV SRCH_BASE,SI
- S_REDO:
- MOV DI,OFFSET SRCH_STR
- MOV BX,SRCH_BASE
- S_CYCLE: MOV AL,[DI]
- MOV AH,AL ;CONVERT AL TO OPPOSITE AND PUT IN AH
- CMP AL,'A'
- JB S_CMP
- CMP AL,'Z'
- JA TSTLO
- XOR AH,20H ;toggle letter case
- JMP SHORT S_CMP
- TSTLO: CMP AL,'a'
- JB S_CMP
- CMP AL,'z'
- JA S_CMP
- XOR AH,20H ;toggle letter case
- S_CMP: CMP BX,LAST_CHAR
- JA END_MCH
- CMP AL,ES:[BX]
- JE S_MCH
- CMP AH,ES:[BX]
- JE S_MCH
- CMP DI,OFFSET SRCH_STR
- JNE S_REDO
- INC BX
- CMP WORD PTR ES:[BX-1],CRLF ;test for EOL marker
- JNE S_BX1
- INC DL
- S_BX1: JMP SHORT S_CMP
-
- S_MCH: INC BX
- CMP DI,OFFSET SRCH_STR
- JNE NO_BSE
- MOV SRCH_BASE,BX
- NO_BSE: ADD DH,DL
- XOR DL,DL
- CMP DI,SRCH_END
- JE YEA_MCH
- INC DI
- JMP SHORT S_CYCLE
- YEA_MCH:
- MOV SRCH_FLG,1
- MOV SI,SRCH_BASE
- DEC SI
- MOV SRCH_BASE,SI
- MOV CURSOR,SI
- XOR BX,BX
- MOV BL,BYTE PTR SRCH_SIZ
- ADD BX,SI
- MOV SRCH_END,BX
- XOR DL,DL
- ADD DX,CURS_POSN
- CMP DH,ROWS
- JBE NEW_S
- XOR DX,DX
- NEW_S:
- POP DS ;ASSUME is no longer valid
- CALL LOCATE
- JMP SHORT END_MCH2
- END_MCH:
- POP DS
- END_MCH2:
- CALL REDO_PROMPT ;redraw the prompt and the screen
- RET
- FIND_STR ENDP
- ;=======================================================================
- ; This routine displays a user help screen
- ;-----------------------------------------------------------------------
- HELP PROC NEAR
- PUSH DS
- PUSH CS
- POP DS
- ASSUME DS:CSEG ;for func-9, display message
- CALL CLR_SCREEN
- MOV DX,OFFSET HELP_SCREEN ;message is at DS:DX in CSEG
- MOV AH,9 ;display message
- INT 21H
- HELP_WAIT_KEY:
- MOV AH,1 ;wait for any key pressed
- INT 16H
- JZ HELP_WAIT_KEY
- MOV AH,0
- INT 16H
- POP DS
- ASSUME DS:NOTHING
- JMP REDO_PROMPT ;redraw the prompt and the screen
- ;(CALL/RETurn)
- HELP ENDP
- ;=======================================================================
- ; This routine prompts for a filename then writes the file. The original
- ; file is renamed to filename.BAK. If an invalid filename is entered, the
- ; speaker is beeped. If the file has not been altered, the edit file is
- ; abandoned and control is immediately returned to DOS.
- ;-----------------------------------------------------------------------
- EXIT PROC NEAR
- PUSH DS ;save in case ESC key
- PUSH ES
- MOV AX,CS
- MOV DS,AX
- MOV ES,AX
- ASSUME DS:CSEG, ES:CSEG
- TEST BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
- JNZ NEXT_LETTER ;(jump was out of range)
- JMP FINISHED ;file has not been altered, no save.
- ;-----------------------
- IS_BACKSPACE:
- CMP DI,NAME_POINTER ;at first letter?
- JLE NEXT_LETTER ;if yes, don't erase it
- MOV BYTE PTR [DI-1],0
- DEC NAME_END
- NEXT_LETTER:
- MOV DH,ROWS
- INC DH ;last row on the screen
- XOR DL,DL ;first column
- MOV SI,OFFSET SAVE_MESS
- PUSH DX
- CALL TTY_STRING ;display a prompt
- POP DX
- ADD DL,9 ;move right 9 spaces
- MOV SI,NAME_POINTER
- CALL TTY_STRING ;display the filename
- XOR AH,AH ;read the next key
- INT 16H
- MOV DI,NAME_END ;this points to the last letter
- OR AL,AL ;is it a real character?
- ; JZ NEXT_LETTER ;ignore special keys
- JZ IS_ESCAPE ;special keys return to edit mode
- CMP AL,1BH ;is it ESCape?
- JE IS_ESCAPE ;continue with exit procedure
- CMP AL,CR ;is it CR?
- JE GOT_NAME
- CMP AL,08H ;is it a backspace?
- JE IS_BACKSPACE
- CMP DI,81H + 65 ;too many letters?
- JG NEXT_LETTER ;if yes, ignore them
- XOR AH,AH ;for new terminal 0 to string
- STOSW ;store the new letter and 0
- INC NAME_END ;name is one character longer
- JMP NEXT_LETTER ;read another keystroke
- ;-----------------------
- IS_ESCAPE:
- POP ES ;get back file segment
- POP DS
- JMP REDO_PROMPT ;redraw the prompt and the screen
- ;(CALL/RETurn) ;return to edit mode
- ;-----------------------
- GOT_NAME:
- MOV DX,NAME_POINTER ;point to the filename
- MOV AX,4300H ;get the file attribute
- INT 21H ;DOS call
- JNC NAME_OK ;if no error, filename is OK
- CMP AX,3 ;was it "path not found" error?
- JE BAD_NAME ;if yes, filename was bad
- NAME_OK:
- MOV SI,OFFSET DOT_$$$ ;point to the ".$$$"
- MOV DI,OFFSET NAME_DOT_$$$
- CALL CHG_EXTENSION ;add the new extension
- MOV DX,OFFSET NAME_DOT_$$$ ;point to temp filename
- MOV CX,0020H ;attribute for new file
- MOV AH,3CH ;function to create file
- INT 21H ;DOS call
- JNC NAME_WAS_OK ;continue if name was OK
- BAD_NAME:
- MOV AX,0E07H ;write a bell character
- INT 10H ;BIOS TTY service
- JMP NEXT_LETTER ;get another letter
- ;-----------------------
- WRITE_ERROR:
- MOV AH,3EH ;close the file
- INT 21H ;DOS call
- JMP BAD_NAME ;filename must be bad
- ;-----------------------
- NAME_WAS_OK:
- XOR DX,DX ;this is the file buffer
- MOV CX,LAST_CHAR ;number of chars in file
- MOV BX,AX ;this is the handle
- MOV AH,40H ;write to the file
- POP DS ;recover the buffer segment
- INT 21H ;write the buffer contents
- POP DS
- JC WRITE_ERROR ;exit on a write error
- CMP AX,CX ;was entire file written?
- JNE WRITE_ERROR ;if not, exit
- PUSH CS
- POP DS ;get the code segment
- MOV AH,3EH ;close the temp file
- INT 21H ;DOS call
- MOV SI,OFFSET DOT_BAK ;point to the ".BAK"
- MOV DI,OFFSET NAME_DOT_BAK
- CALL CHG_EXTENSION ;make the backup filename
- MOV DX,OFFSET NAME_DOT_BAK ;point to the backup name
- MOV AH,41H ;delete existing backup file
- INT 21H ;DOS call
- MOV DI,OFFSET NAME_DOT_BAK
- MOV DX,NAME_POINTER
- MOV AH,56H
- INT 21H ;DOS call
- MOV DI,NAME_POINTER ;point to new filename
- MOV DX,OFFSET NAME_DOT_$$$ ;point to temporary file
- MOV AH,56H ;rename temp to new file
- INT 21H ;DOS call, rename
- POP AX ;restore the stack
- POP AX
- JMP SHORT FINISHED
- ;(To return to DOS)
- EXIT ENDP
- ;-----------------------------------------------------------------------
- ; This routine prompts for a verify keystroke then exits without saving
- ; the file. If the file has not been altered, the edit file is abandoned
- ; and control is immediately returned to DOS.
- ;-----------------------------------------------------------------------
- ABORT PROC NEAR
- PUSH CS
- POP DS
- ASSUME DS:CSEG
- TEST BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
- JZ FINISHED ;file has not been altered.
- MOV DH,ROWS ;last row on display
- INC DH ;bottom row on screen
- XOR DL,DL ;first column
- MOV SI,OFFSET VERIFY_MESS
- CALL TTY_STRING ;display verify message
- XOR AH,AH ;read the next key
- INT 16H ;BIOS read key routine
- CMP AL,CR ;is it CR?
- JE FINISHED
- OR AL,20H ;convert to lower case
- CMP AL,"y" ;was answer Yes?
- JE FINISHED ;if yes, then we're finished
- CALL REDO_PROMPT ;redraw the prompt and the screen
- PUSH ES
- POP DS ;set DS back to file segment
- RET ;return to edit mode
- ;-----------------------
- FINISHED:
- MOV DX,OFFSET COPYRIGHT
- ;-----------------------
- EXIT_TO_DOS: ;External entry point (DX, message)
- PUSH CS
- POP DS ;point to code segment
- ASSUME DS:CSEG
- CALL CLR_SCREEN ;clear the screen (passes DX through)
- MOV AH,9 ;display error/exit message DS:DX
- INT 21H ;DOS call
- MOV AX,EXIT_CODE ;Exit to DOS with exit code
- INT 21H ;DOS call
- ABORT ENDP
- ;=======================================================================
- ; This routine copies the input filename to CS:DI and changes the extension.
- ;-----------------------------------------------------------------------
- CHG_EXTENSION PROC NEAR
- ASSUME DS:CSEG, ES:CSEG
- PUSH SI
- MOV SI,NAME_POINTER
- CHG_LOOP:
- LODSB
- CMP AL,"." ;look for the extension
- JE FOUND_DOT
- OR AL,AL
- JZ FOUND_DOT
- STOSB ;copy a character
- JMP CHG_LOOP
- ;-----------------------
- FOUND_DOT:
- MOV CX,5 ;five characters in extension
- POP SI
- REP MOVSB ;move new extension in
- RET
- CHG_EXTENSION ENDP
- ;=======================================================================
- ; This routine displays the string at CS:SI at the location in DX. The
- ; remainder of the row is erased. Cursor is put at the end of the line.
- ;-----------------------------------------------------------------------
- TTY_STRING PROC NEAR
- ASSUME DS:CSEG
- PUSH DX
- CALL POSITION ;compute offset into video
- POP DX
- TTY_LOOP:
- LODSB ;load DS:SI to AL
- OR AL,AL ;at end of string yet?
- JZ TTY_DONE
- INC DL
- PUSH DX
- CALL WRITE_INVERSE ;write in inverse video
- POP DX
- JMP TTY_LOOP
- ;-----------------------
- TTY_DONE:
- CALL SET_CURSOR ;move cursor to end of string
- JMP ERASE_EOL ;erase the rest of the line
- ;(CALL/RETurn)
- TTY_STRING ENDP
- ;=======================================================================
- ; This routine clears the screen, leaves registers unaltered.
- ;-----------------------------------------------------------------------
- CLR_SCREEN PROC NEAR
- ASSUME DS:NOTHING
- PUSH AX ;save registers (for INT-24)
- PUSH BX
- PUSH CX
- PUSH DX ;save DX for message address
- MOV DL,79 ;DL = right column
- MOV DH,CS:ROWS ;DH = lower row
- INC DH ;to clear the last line on the screen
- MOV CX,0 ;CH = upper row, CL = left column
- MOV BH,CS:NORMAL ;BH is blank line attribute, 07 = normal video
- MOV AX,0600H ;scroll the cursor up (blank line)
- INT 10H
- XOR DX,DX ;set cursor to top left of screen
- CALL SET_CURSOR
- POP DX
- POP CX
- POP BX
- POP AX
- RET
- CLR_SCREEN ENDP
- ;=======================================================================
- ; This is the control break handler for MS-DOS. It ignores the break.
- ; TED then responds by entering a <Ctrl-C> in the file.
- ;-----------------------------------------------------------------------
- NEWINT23 PROC FAR
- ASSUME DS:NOTHING, ES:NOTHING
- MOV CS:DIRTY_BITS,1 ;to redraw the screen
- CLC ;tell DOS to ignore break
- IRET
- NEWINT23 ENDP
- ;=======================================================================
- ; This is the severe error handler. It homes the cursor before
- ; processing the error.
- ;-----------------------------------------------------------------------
- NEWINT24 PROC FAR
- ASSUME DS:NOTHING, ES:NOTHING
- PUSHF
- CALL CLR_SCREEN ;clear the screen and home the cursor
- POPF
- JMP CS:OLDINT24
- ;(chain to old INT 24 handler)
- NEWINT24 ENDP
- ;=======================================================================
- ; This is the location of the character string search buffer. It occupies
- ; the last three bytes in the program file. The following 64-bytes are used
- ; for the buffer area. The third byte is also used as the program code
- ; check-sum compensation byte.
- ;-----------------------------------------------------------------------
- EVEN
- SRCH_MAX DB 66 ;42H, maximum size of buffer
- SRCH_SIZ DB 0 ;number of char's actually in buffer
- SRCH_STR DB 0 ;start of buffer block
- ;This is the correction byte for the check-sum test
- CHEK_SUM_BYT DB 0103
- ;=======================================================================
- NAME_DOT_$$$ EQU $ +64 ;128 bytes
- NAME_DOT_BAK EQU $+80H +64 ;128 bytes
- UNDO_BUFFER EQU $+100H +64 ;256 bytes, Del key buffer
- LINE_BUFFER EQU $+200H +64 ;256 bytes, Delete line, EOL
- END_BUFFER EQU $+300H +64 +15 ;end of buffers, file segment follows
- ; +15 is for paragraph rounding
- CSEG ENDS
- ;-----------------------------------------------------------------------
- FILE_SEG SEGMENT
- FILE_SEG ENDS
- END START