www.pudn.com > ted2.zip > TED2.ASM


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  key actually  
; adds two characters, Carriage-return (ASCII 13) and Line-feed (ASCII 10),  
; also known as a "hard carriage return".  The  key inserts the ASCII 9  
; tab character, and advances the screen cursor to the next column that is  
; an even multiple of eight.  The  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  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 , 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  code to be  
; entered by pressing the  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 		Enters the  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 , move QUIT to . 
;	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  as alias for  SEARCH (usage in BSE editor). 
;	Add  as alias for  SEARCH AGAIN (usage in BSE editor). 
;	Add  as alias for , Delete to end of line. 
;	Add  as alias for , 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  as key to enter the  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  and .  
;	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 -  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  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  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  is detected,  
; a  pair is added as the EOL marker.  If the scan code for  
;  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  key scan code? 
		JE	NEW_LINE	;if yes, make new line: . 
 
		CMP	AH,14		;was it the  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  - 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  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  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.   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. ,  
;----------------------------------------------------------------------- 
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  without , 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  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