TED2.ASM
上传用户:liaison
上传日期:2007-01-05
资源大小:31k
文件大小:77k
源码类别:

编辑器/阅读器

开发平台:

Asm

  1. NAME TED
  2. PAGE 58,132
  3. TITLE TED -- the Tiny EDitor
  4. ;=======================================================================
  5. ; TED.ASM -- The Tiny EDitor.
  6. ; PC Magazine * Tom Kihlken * 11/15/88
  7. ;
  8. ; See the article "The tiniest editor you'll ever need" by Tom Kihlken, 
  9. ; in the November 15, 1988 issue of PC Magazine for more detail than is 
  10. ; presented here.  Portions of this text are excerpted from that article.  
  11. ; The source listing, itself, was copied directly from that article and 
  12. ; altered as appropriate to add comments or change or improve the program.
  13. ; The use of self-modifying code for "NO_DESNOW" is discussed in the article.
  14. ; SEGment register usage have been cleaned up to reduce the size of the code.
  15. ;
  16. ; TED follows normal text conventions: pressing the <Enter> key actually 
  17. ; adds two characters, Carriage-return (ASCII 13) and Line-feed (ASCII 10), 
  18. ; also known as a "hard carriage return".  The <Tab> key inserts the ASCII 9 
  19. ; tab character, and advances the screen cursor to the next column that is 
  20. ; an even multiple of eight.  The <Backspace> key deletes the character to 
  21. ; its immediate left ("destructive" backspace) and combines two lines if it 
  22. ; is pressed while in the first column.  The Backspace code (Ctrl-H) may be 
  23. ; entered in the file as a control code.  TED2 allows the ASCII codes for 
  24. ; Carriage-Return (Ctrl-M) and Line-feed (Ctrl-J) to independently be entered 
  25. ; into the file as control codes.  Because of this, TED2 rigidly enforces 
  26. ; a convention that once the <Ctrl-M><Ctrl-J> pair is formed it becomes an 
  27. ; End-of-line marker, and may not be separated again.   
  28. ;
  29. ; Like DOS, TED lets you enter any character (except <Nul>, value 00) by 
  30. ; holding down the Alt key, typing the decimal value of its ASCII code on 
  31. ; the numeric keypad, then releasing Alt.  This gives you access both to 
  32. ; nonprinting codes below ASCII 32 and to the upper-order (ASCII 128 to 255) 
  33. ; characters in the extended IBM set.  TED2 allows the <Nul> code to be 
  34. ; entered by pressing the <Shft-F1> key.
  35. ;
  36. ; NOTE: Unassigned keyboard codes are treated as no-operations.
  37. ;
  38. ; The TED Keypad commands are:
  39. ; Key Description
  40. ; Up Arrow Moves cursor up one row
  41. ; Down Arrow Moves cursor down one row
  42. ; Left Arrow Moves cursor left one column
  43. ; Right Arrow Moves cursor right one column
  44. ; PgUp Moves text window up one page
  45. ; PgDn Moves text window down one page
  46. ;>Home Moves cursor to start of row (if at home, next up)
  47. ;>End Moves cursor to end of row (if at end, next end down)
  48. ; Ins Toggles insert/overstrike mode
  49. ; Del Deletes character (right) at cursor (saved in UnDo)
  50. ; Backspace Deletes character (left) at cursor (not saved in UnDo)
  51. ; Ctrl-PgUp Moves to top of file
  52. ;>Ctrl-Home Moves to top of file (alias)
  53. ; Ctrl-PgDn Moves to bottom of file
  54. ;>Ctrl-End Moves to bottom of file (alias)
  55. ; Ctrl-Right Arrow Moves text window right eight columns
  56. ; Ctrl-Left Arrow Moves text window left eight columns
  57. ;
  58. ; Alt-S Search Search for (case insensitive) character string
  59. ; Alt-A Search Again Search again for string
  60. ; Alt-D Del EOL Deletes from cursor to the end of line
  61. ;
  62. ; The TED Editing Functions are:
  63. ; Key Function Operation
  64. ; F1 Help  Help screen
  65. ; ShftF1 <Nul> Enters the <Nul> code (value 00) in the file
  66. ; F2 Exit Save changes and exit (creates a .BAK file)
  67. ; ShftF2 Quit Exit without saving changes
  68. ; F3 Print Prints the marked text
  69. ; F4 Mark Toggles mark state on/off
  70. ; F5 Cut Moves marked text to paste buffer
  71. ; ShftF5 Paste Inserts contents of paste buffer (64K char's max)
  72. ; F6 Search Search for (case insensitive) character string
  73. ; ShftF6 Search Again Search again for string
  74. ; F7 UnDo Replaces recently DELeted characters (256 char's max)
  75. ; F8 Del EOL Deletes from cursor to the end of line
  76. ; ShftF8 Del L Deletes the current line (MultiEdit)
  77. ; F9 Del L Deletes the current line
  78. ; F10 Udel L Inserts the last deleted line (256 char's max)
  79. ;
  80. ; In addition to the 64K Text buffer (where the edit file is maintained), 
  81. ; there are three other important buffers, as indicated above.  
  82. ;   1.) The paste buffer is a 64K character buffer used for MARK/CUT/PASTE of 
  83. ; sections of the file.
  84. ;   2.) The line buffer is a 256 character buffer used to save the last 
  85. ;  deleted line of text (used with F8, F9 and F10).
  86. ;   3.) The UnDo buffer is a 256 character buffer used to save the just 
  87. ; deleted characters at the current cursor location.  It works with 
  88. ;  the "DEL" key, but only the last character with the "Backspace" key.  
  89. ;  It also saves overwritten characters in the Overstrike mode.  
  90. ;  Deletions are restored with "F7" UnDo.
  91. ;
  92. ; NOTE: There is a severe subroutine nesting violation in the TED key scan 
  93. ; routine.  BAD_KEY from within the keyboard scanning loop is a junp to 
  94. ; read next key.  The BAD_KEY subroutine calls through the DISPATCH_TABLE 
  95. ; do not have a corresponding return to equalize the stack.  This was 
  96. ; partially compensated for by making the stack humongous.  TED 1.0 as 
  97. ; published in PC Magazine could eventually overflow the stack and crash the 
  98. ; system.  TED2 has corrected this problem by making a stub subroutine for 
  99. ; the DISPATCH_TABLE BAD_KEY subroutine CALLs.
  100. ;
  101. ; TED was modified by James E. Galbraith, Dec 18, 1988.
  102. ; The changes are of several types.  Compatability with other editors.  
  103. ; Correction of errors and questionable code.  Reordering of program modules 
  104. ; to make it easier to follow the listing.  Addition of meaningful comments.
  105. ; These modifications include:
  106. ; Change F2 "UnDo" to "Exit" (for BSE compatibility).
  107. ; Change F7 "Exit" to "UnDo".
  108. ; Make CTRL-HOME alias to CTRL-PGUP, to home the cursor (for BSE).
  109. ; Make CTRL-END alias to CTRL-PGDN, cursor to end of file (for BSE).
  110. ; JMP instructions outside modules instead of CALL/RETurn are commentd.
  111. ; Assignment of DS was sometimes ambiguous.  
  112. ;
  113. ; Modified by James E. Galbraith, June 1989.
  114. ; The changes are in two groups.  Those taken from TEDPLUS (apparently also 
  115. ; written by Tom Kihlken), which was acquired from a bulletin board service, 
  116. ; and my own changes.
  117. ; Add SEARCH and SEARCH AGAIN as F6 and Shft-F6, from TEDPLUS.
  118. ; Delete CPM style Ctrl-Z End-of-file code, from TEDPLUS.
  119. ; "Enter any key code" from TEDPLUS was included, but not like TEDPLUS
  120. ; End-of-line was changed to CR-LF as in TEDPLUS.  CR or LF codes may be 
  121. ;   entered separately.
  122. ; My own changes are:
  123. ; Close the source file if it has been opened.  This was not done by TED.
  124. ; Add a HELP screen as <F1>, move QUIT to <Shft-F2>.
  125. ; Fix the SEARCH inverse video to turn off when any key is pressed.
  126. ; Add DOS version check, needs version 2.0 or higher to run.
  127. ; Add a program checksum test for verification of file integrity.
  128. ; Add <Alt-S> as alias for <F6> SEARCH (usage in BSE editor).
  129. ; Add <Alt-A> as alias for <Shft-F6> SEARCH AGAIN (usage in BSE editor).
  130. ; Add <Alt-D> as alias for <Shft-F8>, Delete to end of line.
  131. ; Add <Shft-F8> as alias for <F9>, Delete Line (for future expansion).
  132. ; If the file has not been altered, don't prompt for save or quit.
  133. ; On QUIT, accept a CR as confirmation of intention to abandon file.
  134. ; Add <Shft-F1> as key to enter the <Nul> character, 00.
  135. ; If a CR and LF code are made to be ajacent, they become an EOL marker, 
  136. ;   and may not then be separated.  This can occur in several ways that 
  137. ;   all include entering the codes <Crtl-M> and <Ctrl-J>. 
  138. ; A key entry will interrupt a screen update that is in progress.
  139. ;   
  140. ; Assemble the TED2.ASM source file to TED2.COM by using the MASM.EXE assembler, 
  141. ; the linker LINK.EXE, and the file conversion utility EXE2BIN.EXE, as follows:
  142. ; The checksum byte can be obtained with TEST.BAT (included with TED2.ASM).
  143. ;
  144. ; MASM TED2;
  145. ; LINK TED2;
  146. ; EXE2BIN TED2 TED2.COM
  147. ;-----------------------------------------------------------------------
  148. CSEG SEGMENT
  149. ASSUME CS:CSEG, DS:CSEG, ES:CSEG
  150. ORG 0100H
  151. START:
  152. JMP BEGIN
  153. ;-----------------------------------------------------------------------
  154. ; Local data area in CSEG.
  155. ;-----------------------------------------------------------------------
  156. ; ASCII character values used in the program.
  157. TAB EQU 9
  158. CR EQU 13
  159. LF EQU 10
  160. CRLF EQU 0A0DH
  161. ; Character strings and data
  162. COPYRIGHT DB "TED 1.0 (C) 1988 Ziff Communications Co.,"
  163. DB "PC Magazine, 11/15/88, by Tom Kihlken"
  164. DB CR,LF,"TED 2.1, 9/12/89, by James E. Galbraith"
  165. DB CR,LF,"$"
  166. ;(JEG)
  167. HELP_SCREEN DB 9,9,'TED - the Tiny EDitor (any key to edit)',CR
  168.                 DB      LF,LF,9,'F1 - Help',9,9,9,'Shft-F1 - <NUL> char'
  169. DB CR,LF,9,'F2 - Exit and save',9,9,'Shft-F2 - Quit'
  170. DB CR,LF,9,'F3 - Print marked',9,9,'Shft-F3 - Form-feed'
  171. DB CR,LF,9,'F4 - Mark toggle'
  172. DB CR,LF,9,'F5 - Cut marked',9,9,9,'Shft-F5 - Paste'
  173. DB CR,LF,9,'F6 - String search',9,9,'Shft-F6 - '
  174. DB 'Search again'
  175. DB CR,LF,9,'F7 - Undo <Del> or Ovr'
  176. DB CR,LF,9,'F8 - Delete to EOL' ;** ,9,9,'Shft-F8 - '
  177. ;** DB 'Delete Line'
  178. DB CR,LF,9,'F9 - Delete Line'
  179. DB CR,LF,9,'F10 - Un-Delete line',LF
  180. DB CR,LF,9,'Ctrl-L/R arrow - Move window'
  181. DB CR,LF,9,'Ctrl-Home - to top'
  182. DB CR,LF,9,'Ctrl-End - to EOF',LF
  183. DB CR,LF,9,'Esc - From Exit'
  184. DB CR,LF,'$',7,1AH
  185. ;from JEG and TEDPLUS
  186. PROMPT_STRING DB "1Help",0 ;F1
  187. DB "2Exit",0 ;F2
  188. DB "3Print",0 ;F3
  189. DB "4Mark",0 ;F4
  190. DB "5Cut",0 ;F5
  191. DB "6Search",0 ;F6
  192. DB "7UnDo",0 ;F7
  193. DB "8Del EOL",0 ;F8
  194. DB "9Del L",0 ;F9
  195. DB "10Udel L",0,0 ;F10
  196. PROMPT_LENGTH = $ - OFFSET PROMPT_STRING
  197. FILE_TOO_BIG DB "File too big$"
  198. READ_ERR_MESS DB "Read error$"
  199. MEMORY_ERROR DB "Not enough memory$"
  200. ;(JEG)
  201. CHEK_SUM_MESS DB "TED altered$"
  202. DOS_2_MESS DB "Needs DOS 2.0$"
  203. VERIFY_MESS DB "Lose Changes (Y)?",0
  204. SAVE_MESS DB "Save as: ",0
  205. DOT_$$$ DB ".$$$",0
  206. DOT_BAK DB ".BAK",0
  207. ;from TEDPLUS, string search
  208. SRCH_PROMPT DB "SEARCH> ",0
  209. ;SRCH_MAX DB 66 ;(moved to file end to reduce file size)
  210. ;SRCH_SIZ DB 0
  211. ;SRCH_STR DB 66 DUP (0)
  212. SRCH_FLG DB 0 ;0=normal, 1=search successful (inverse)
  213. SRCH_END DW 0
  214. SRCH_BASE DW 0
  215. SRCH_CLR DB 0F0H ;244
  216. DIRTY_BITS DB 03H ;1=update screen, 2=cursor 4=cur. line
  217. DIRTY_FILE DB 0 ;0=file not altered, FF=file altered
  218. NORMAL DB 07H ;video attribute bits
  219. INVERSE DB 70H ;video (inverse)
  220. LEFT_MARGIN DB 0 ;column number of screen left margin
  221. MARGIN_COUNT DB 0
  222. INSERT_MODE DB 01H ;1=INSert, 0=Overstrike, 2or3=Read Only
  223. INSERT_CODE DB 'OIRR' ;indexed code for display screen
  224. MARK_MODE DB 0 ;toggle, FF=MARK is on.
  225. ROWS DB 23 ;Rows available on display screen
  226. SAVE_COLUMN DB 0
  227. SAVE_ROW DB 0
  228. LINE_FLAG DB 0
  229. EVEN ;"word align" (for 16-bit bus accesses)
  230. NAME_POINTER DW 81H ;offset of command tail in PSP
  231. NAME_END DW 81H ;end of tail
  232. VIDEO_STATUS_REG LABEL DWORD ;(alias for use by LES instruction)
  233. STATUS_REG DW 0 ;video status register offset
  234. VIDEO_SEG DW 0B000H ;video segment, Mono=0B000, other 0B800
  235. LINE_LENGTH DW 0 ;number of bytes in current line
  236. UNDO_LENGTH DW 0 ;number of DELeted bytes in UnDo buffer
  237. CURS_POSN DW 0 ;Cursor, Hi is row, Low is column
  238. MARK_START DW 0FFFFH ;MARK text for CUT/PASTE or Print
  239. MARK_END DW 0
  240. MARK_HOME DW 0
  241. TOP_OF_SCREEN DW 0 ;address in text file of Top-of-screen
  242. CURSOR DW 0 ;address in text file of cursor
  243. LAST_CHAR DW 0 ;address of last character in file.
  244. COLUMNSB LABEL BYTE ;alias BYTE definition
  245. COLUMNS DW 0
  246. PASTE_SEG DW 0 ;segment address of PASTE buffer
  247. PASTE_SIZE DW 0 ;size of block in PASTE buffer
  248. PAGE_PROC DW 0 ;pointer used by PGUP and PGDN
  249. EXIT_CODE DW 4C00H ;DOS INT 21H, Func 4CH, exit with code
  250. OLDINT24 DD 0 ;pointer to DOS critical error handler
  251. DISPATCH_BASE EQU 59   ;initial offset for a PASCAL type CASE list
  252. DISPATCH_TABLE DW HELP   ;59;F1, Help screen (common usage)
  253. DW EXIT   ;60;F2, Save changes and exit (from BSE)
  254. DW PRINT   ;61;F3, Print the marked text
  255. DW MARK   ;62;F4, Toggle mark state on/off
  256. DW CUT   ;63;F5, Move marked text to buffer
  257. DW FIND_STR  ;64;F6, Search for text string
  258. DW UNDO   ;65;F7, Replace recently deleted chars
  259. DW DEL_EOL   ;66;F8, Delete from cursor to EOL
  260. DW DEL_L   ;67;F9, Delete the current line
  261. DW UDEL_L   ;68;F10, Insert the last deleted line
  262. DW BAD_KEY   ;69;(NumLock)
  263. DW BAD_KEY   ;70;(ScrollLock)
  264. DW HOME_KEY  ;71;Home/7
  265. DW UP   ;72;Up/8
  266. DW PGUP   ;73;PgUp/9
  267. DW BAD_KEY   ;74;(-)
  268. DW LEFT   ;75;Left/4
  269. DW BAD_KEY   ;76;(5)
  270. DW RIGHT   ;77;Right/6
  271. DW BAD_KEY   ;78;(+)
  272. DW END_KEY   ;79;End/1
  273. DW DOWN   ;80;Down/2
  274. DW PGDN   ;81;PgDn/3
  275. DW INSERT   ;82;Ins/3
  276. DW DEL_CHAR  ;83;Del/.
  277. DW NUL_CHAR  ;84;Shft-F1 -- Add NUL character to file
  278. DW ABORT   ;85;Shft-F2 -- Quit and abandon changes
  279. DW PRINT_FF  ;86;Shft-F3 -- Print a form-feed character
  280. DW BAD_KEY   ;87;Shft-F4
  281. DW PASTE   ;88;Shft-F5 -- Insert contents of Paste buffer
  282. DW FIND_STR  ;89;Shft-F6 -- Search again for string
  283. DW BAD_KEY   ;90;Shft-F7
  284. DW DEL_L   ;91;Shft-F8 -- Delete line (Multi-Edit)
  285. DISPATCH_END EQU 92
  286. ;--------------------------------
  287. ; gap in keyboard scan code assignments
  288. ;--------------------------------
  289. DISP_CURS_BASE EQU 115
  290. DW SH_LEFT   ;115;Ctrl-Left arrow
  291. DW SH_RIGHT  ;116;Ctrl-Right arrow
  292. DW BOTTOM    ;117;Ctrl-End
  293. DW CTRL_PGDN ;118;Ctrl-PgDn
  294. DW TOP   ;119;Ctrl-Home
  295. DISP_CURS_END EQU 120
  296. ;** DW CTRL_PGUP ;132;Ctrl-PgUp
  297. ;---------------------------------
  298. ; The following constant is a machine instruction that removes the CGA desnow 
  299. ; delay.  It is inserted into the code for EGA, VGA, and mono displays.
  300. ; See the article in PC-Magazine for further discussion.
  301. NO_DESNOW = (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256 + 0EBH ;opcode JMP SHORT
  302. ;=======================================================================
  303. ; We start by initialize the display, then allocate memory for the file
  304. ; and paste segments.  Parse the command line for the filename, if one was 
  305. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  306. ;-----------------------------------------------------------------------
  307. BEGIN:
  308. MOV AH,30H ;get DOS version (JEG new)
  309. INT 21H
  310. CMP AL,2
  311. JAE DOS_2_UP
  312. MOV EXIT_CODE,0 ;is DOS version 1, exit with function 0.
  313. MOV DX,OFFSET DOS_2_MESS ;message "Needs DOS 2.0"
  314. ;**short JMP EXIT_TO_DOS
  315. JMP SHORT EXIT_22_DOS ;(saves a byte)
  316. ;-----------------------
  317. DOS_2_UP:
  318. ;JEG new -- program code checksum test
  319. MOV SI,100H ;start of program file.
  320. MOV SP,SI ;set stack pointer to top of PSP.
  321. MOV CX,OFFSET CHEK_SUM_BYT - 0100H ;size of program file.
  322. MOV AL,CHEK_SUM_BYT ;load checksum correction factor byte.
  323. CHKSUM_LOOP: ADD AL,[SI] ;add all program code bytes together.
  324. INC SI
  325. LOOP CHKSUM_LOOP
  326. CMP AL,0 ;is program checksum zero?
  327. JZ CHEKSUM_IS_OK ;yes, continue with program
  328. NEG AL ;make error into correction factor.
  329. MOV BYTE PTR EXIT_CODE,AL ;save errorlevel code for exit.
  330. MOV DX,OFFSET CHEK_SUM_MESS ;message "TED altered".
  331. ;**short JMP EXIT_TO_DOS ;error message and exit to DOS
  332. ;EXIT_22_DOS: JMP SHORT EXIT_2_DOS ;error message and exit to DOS
  333. EXIT_22_DOS: JMP EXIT_2_DOS ;error message and exit to DOS
  334. ;-----------------------
  335. CHEKSUM_IS_OK:
  336. XOR AX,AX
  337. MOV DS,AX ;zero DS
  338. ASSUME DS:NOTHING
  339. MOV BL,10H
  340. MOV AH,12H ;get EGA info
  341. INT 10H
  342. CMP BL,10H ;did BL change?
  343. JE NOT_EGA ;if not, no EGA in system
  344. TEST BYTE PTR DS:[0487H],8 ;is EGA active?
  345. JNZ NOT_EGA
  346. MOV WORD PTR CS:HWAIT,NO_DESNOW ;get rid of desnow
  347. MOV AX,DS:[0484H] ;get number of rows
  348. DEC AL ;last row is for prompt line
  349. MOV CS:[ROWS],AL ;save the number of rows
  350. NOT_EGA:
  351. MOV AX,DS:[044AH] ;get number of columns
  352. MOV CS:COLUMNS,AX ;and store it
  353. MOV AX,DS:[0463H] ;address of display card
  354. ADD AX,6 ;add six to get status port
  355. PUSH CS
  356. POP DS
  357. ASSUME DS:CSEG
  358. MOV STATUS_REG,AX
  359. CMP AX,3BAH ;is this a MONO display?
  360. JNE COLOR ;if not, must be a CGA
  361. MOV WORD PTR HWAIT,NO_DESNOW ;get rid of desnow
  362. JMP SHORT MOVE_STACK
  363. COLOR:
  364. MOV VIDEO_SEG,0B800H ;segment for color card
  365. XOR BH,BH ;use page zero
  366. MOV AH,8 ;get current attribute
  367. INT 10H
  368. AND AH,77H ;turn off blink and high intensity
  369. MOV NORMAL,AH ;save the normal attribute
  370. XOR AH,01110111B ;flip the color bits
  371. MOV INVERSE,AH
  372. OR AH,80H
  373. MOV SRCH_CLR,AH ;search is inverse/blink
  374. MOVE_STACK:
  375. MOV BX,OFFSET END_BUFFER
  376. ;**rounding ADD BX,15 ;add offset value for SEG rounding up
  377. MOV CL,4 ;convert program size to 
  378. SHR BX,CL ; paragraphs
  379. MOV AH,4AH ;deallocate unused memory
  380. INT 21H ;DOS call
  381. MOV BX,1000H ;request 64K for file segment
  382. MOV AH,48H
  383. INT 21H ;DOS call
  384. MOV ES,AX
  385. ASSUME ES:FILE_SEG
  386. MOV AH,48H ;request 64K for paste buffer
  387. INT 21H ;DOS call
  388. JNC GOT_ENOUGH ;if enough memory, continue
  389. NOT_ENOUGH:
  390. MOV DX,OFFSET MEMORY_ERROR
  391. EXIT_2_DOS: JMP EXIT_TO_DOS ;jump island to allow SHORT jumps.
  392. ;-----------------------
  393. GOT_ENOUGH:
  394. MOV PASTE_SEG,AX ;use this for the paste buffer
  395. GET_FILENAME:
  396. MOV SI,80H ;point to command tail in PSP
  397. MOV CL,[SI] ;get number of characters in tail
  398. XOR CH,CH ;make it a word
  399. INC SI ;point to first character
  400. PUSH SI
  401. ADD SI,CX ;point to last character
  402. MOV BYTE PTR [SI],0 ;make it an ASCIIZ string (clear the CR)
  403. MOV NAME_END,SI ;save pointer to last character
  404. POP SI ;get back pointer to filename
  405. JCXZ NO_FILENAME ;if no params, just exit
  406. CLD
  407. DEL_SPACES:
  408. LODSB ;get character into AL
  409. CMP AL," " ;is it a space?
  410. JNE FOUND_LETTER
  411. LOOP DEL_SPACES
  412. FOUND_LETTER:
  413. DEC SI ;backup pointer to first letter
  414. MOV NAME_POINTER,SI ;save pointer to filename
  415. MOV DX,NAME_POINTER
  416. MOV AX,4300H ;get file attribute byte (in CL)
  417. INT 21H ;DOS call
  418. JC ATTRIB_ERROR
  419. AND CL,1 ;keep bit-0, read-only status
  420. ADD CL,CL ;shift RO bit up 
  421. OR INSERT_MODE,CL ;save as index modifier value
  422. ATTRIB_ERROR:
  423. MOV DX,SI
  424. MOV AX,3D00H ;setup to open file
  425. INT 21H ;DOS call
  426. ; If no carry, Then the opened file handle is in AX
  427. ; If no carry, Then the opened file handle is in AX
  428. JC NO_FILENAME ;if we can't open, must be new file
  429. FILE_OPENED:
  430. PUSH ES
  431. POP DS ;DS has file segment also
  432. ASSUME DS:FILE_SEG
  433. MOV BX,AX ;get the handle into BX
  434. XOR DX,DX ;point to file buffer, DS:DX
  435. MOV CX,0FFFEH ;read almost 64K bytes
  436. MOV AH,3FH ;read from file or device
  437. ; BX = file handle
  438. INT 21H ;DOS call
  439. ; If no carry, Then AX contains number of bytes read
  440. MOV DI,AX ;number of bytes read in
  441. JNC FILE_READ_OK ;if no error, take jump
  442. MOV DX,OFFSET READ_ERR_MESS
  443. ;-----------------------
  444. ; the file has been opened, it should now be closed. (JEG)
  445. ;-----------------------
  446. CLOSE_ERR_EXIT:
  447. MOV AH,3EH ;close the opened file
  448. ; BX = file handle
  449. INT 21H
  450. JMP SHORT EXIT_2_DOS
  451. ;-----------------------
  452. FILE_READ_OK:
  453. MOV LAST_CHAR,DI ;save the file size
  454. CMP CX,AX ;did the buffer fill?
  455. MOV DX,OFFSET FILE_TOO_BIG
  456. JE CLOSE_ERR_EXIT ;if yes, it is too big
  457. MOV AH,3EH ;close the file
  458. ; BX = file handle
  459. INT 21H
  460. ;**dirty MOV BYTE PTR CS:DIRTY_FILE,0 ;file opened but not altered.
  461. NO_FILENAME:
  462. PUSH ES
  463. PUSH ES ;save the file segment
  464. PUSH CS
  465. POP DS
  466. ASSUME DS:CSEG
  467. ;-----------------------
  468. ;INT 24 is the critical error handler
  469. ;-----------------------
  470. MOV AX,3524H ;get INT 24 vector
  471. INT 21H ;DOS call
  472. MOV WORD PTR OLDINT24,BX   ;store the offset
  473. MOV WORD PTR OLDINT24+2,ES ;and the segment
  474. MOV DX,OFFSET NEWINT24 ;point to new vector
  475. MOV AX,2524H ;now change INT 24 vector
  476. INT 21H ;DOS call
  477. ;-----------------------
  478. ;INT 23 is the CTRL-Break or CTRL-C handler
  479. ;-----------------------
  480. MOV DX,OFFSET NEWINT23
  481. MOV AX,2523H ;set the INT 23 vector
  482. INT 21H ;DOS call
  483. POP ES ;get back file segment
  484. POP DS
  485. ASSUME DS:FILE_SEG
  486. CALL REDO_PROMPT ;draw the prompt line
  487. ;-----------------------------------------------------------------------
  488. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  489. ;-----------------------------------------------------------------------
  490. READ_A_KEY:
  491. CMP MARK_MODE,0 ;is the mark state on?
  492. JZ MARK_OFF ;if not, skip this
  493. OR DIRTY_BITS,4 ;refresh the current row
  494. MOV DX,CURS_POSN
  495. CMP SAVE_ROW,DH ;are we on the save row?
  496. JE SAME_ROW ;if yes, then redo the row only
  497. OR DIRTY_BITS,1 ;refresh the whole screen
  498. SAME_ROW:
  499. MOV AX,CURSOR ;get cursor location
  500. MOV BX,MARK_HOME ;get the anchor mark position
  501. CMP AX,BX ;moving backward in file?
  502. JAE SAME1
  503. MOV MARK_START,AX ;switch start and end positions
  504. MOV MARK_END,BX
  505. JMP SHORT MARK_OFF
  506. SAME1:
  507. MOV MARK_END,AX ;store start and end marks
  508. MOV MARK_START,BX
  509. MARK_OFF:
  510. CALL DISPLAY_SCREEN ;redraw the screen
  511.                 XOR     AH,AH           ;read the next key (wait if none ready)
  512. INT 16H ;BIOS call
  513. ; AL = ASCII code or 0 (for function keys)
  514. ; AH = scan code
  515.                 TEST    SRCH_FLG,0FFH
  516. JZ CHECK_KEY ;jump if inverse not on
  517. MOV SRCH_FLG,0 ;turn off highlight
  518. OR DIRTY_BITS,1 ;redraw screen (next time)
  519. CHECK_KEY:
  520. OR AL,AL ;is this an extended code?
  521. JZ IS_EXTENDED_CODE ;(jump if not an ASCII character)
  522.   CALL INSERT_KEY ;put this ASCII character in the file
  523. ;**short JMP READ_A_KEY ;get another key
  524. JMP SHORT RD_NEXT_KEY ;get another key
  525. ;---------------------------------------
  526. IS_EXTENDED_CODE:
  527. ;-----------------------
  528. ; The following code is for "orphan" key codes and alias keys
  529. ;-----------------------
  530. CMP AH,132 ;is it Ctrl-PgUp? (an orphan code)
  531. JNE NOT_CT_PGUP
  532. CALL CTRL_PGUP
  533. ;**short JMP READ_A_KEY
  534. JMP SHORT RD_NEXT_KEY ;get another key
  535. ;-----------------------
  536. NOT_CT_PGUP:
  537. CMP AH,32 ;is it Alt-D (MultiEdit Del-EOL)?
  538. JNE NOT_ALT_D
  539. MOV AH,66 ;substitute scan code for F8
  540. NOT_ALT_D:
  541. CMP AH,31 ;is it Alt-S (BSE string search)?
  542. JNE NOT_ALT_S
  543. MOV AH,64 ;substitute scan code for F6
  544. NOT_ALT_S:
  545. CMP AH,30 ;is it Alt-A (BSE search again)?
  546. JNE NOT_ALT_A
  547. MOV AH,89 ;substitute scan code for Shft-F6
  548. NOT_ALT_A:
  549. ;-----------------------
  550. ; The following code sets up a PASCAL style CASE statement.
  551. ;-----------------------
  552. CMP AH,DISPATCH_END ;split the dispatch table
  553. JB DO_DISPATCH
  554. ;-----------------------
  555. ; offset cursor group of keys to join the regular dispatch table.
  556. ;-----------------------
  557. CMP AH,DISP_CURS_BASE
  558. JB RD_NEXT_KEY
  559. CMP AH,DISP_CURS_END
  560. JAE RD_NEXT_KEY
  561. SUB AH,LOW (DISP_CURS_BASE - DISPATCH_END) ;close table gap
  562. DO_DISPATCH:
  563. ;-----------------------
  564. ; This is a PASCAL style CASE statement.
  565. ;-----------------------
  566. MOV BX,AX ;put AH offset value in BX, AL=0
  567. XCHG BL,BH ;make into a proper word
  568. SUB BX,DISPATCH_BASE ;zero offset for dispatch table jump
  569. JC RD_NEXT_KEY ;too low, not in table
  570. ADD BX,BX ;make into word
  571. CALL CS:DISPATCH_TABLE[BX] ;call the key procedure
  572. RD_NEXT_KEY: JMP READ_A_KEY ;then read another key
  573. ;=======================================================================
  574. ; KEYBOARD and CURSOR services
  575. ;=======================================================================
  576. ; These two routines shift the display right or left to allow editing 
  577. ; files which contain lines longer than 80 columns.  Starting with TED2, 
  578. ; they are proper subroutines.  
  579. ;-----------------------------------------------------------------------
  580. SH_LEFT PROC NEAR
  581. CMP LEFT_MARGIN,0 ;at start of line already?
  582. JE NO_SHIFT ;if yes,then don't shift
  583. SUB LEFT_MARGIN,8 ;move the window over
  584. JMP SHORT SH_RETURN
  585. SH_LEFT ENDP
  586. ;-----------------------------------------------------------------------
  587. SH_RIGHT PROC NEAR
  588. CMP LEFT_MARGIN,255 - 8 ;past max allowable margin?
  589. JAE NO_SHIFT ;then can't move any more
  590. ADD LEFT_MARGIN,8 ;this moves the margin over
  591. SH_RETURN:
  592. CALL CURSOR_COL ;compute column for cursor
  593. MOV SAVE_COLUMN,DL ;save the current column
  594. OR DIRTY_BITS,1 ;redraw the screen
  595. NO_SHIFT:
  596. ;**dispatch JMP READ_A_KEY
  597. ;**bad_key RET
  598. SH_RIGHT ENDP
  599. ;-----------------------------------------------------------------------
  600. ; DISPATCH_TABLE calls to BAD_KEY now go here so that the stack can be 
  601. ; kept equallized.  
  602. ;-----------------------------------------------------------------------
  603. BAD_KEY PROC NEAR
  604. RET
  605. BAD_KEY ENDP
  606. ;=======================================================================
  607. ; This routine moves the cursor to the top of the file.
  608. ;-----------------------------------------------------------------------
  609. TOP PROC NEAR
  610. XOR AX,AX ;get a zero into AX
  611. MOV CURSOR,AX ;cursor to start of file
  612. MOV TOP_OF_SCREEN,AX
  613. MOV LEFT_MARGIN,AL ;move to far left margin
  614. MOV CURS_POSN,AX ;home the cursor
  615. MOV SAVE_COLUMN,AL ;save the cursor column
  616. MOV DIRTY_BITS,3 ;redraw the screen and cursor
  617. RET
  618. TOP ENDP
  619. ;=======================================================================
  620. ; This routine moves the cursor to the bottom of the file.
  621. ;-----------------------------------------------------------------------
  622. BOTTOM PROC NEAR
  623. MOV DH,ROWS ;get screen size
  624. MOV SI,LAST_CHAR ;point to last character
  625. ;-----------------------
  626. ; from TEDPLUS
  627. DEC SI
  628. ;-----------------------
  629. MOV LEFT_MARGIN,0 ;set window to start of line
  630. CALL LOCATE ;adjust the cursor screen position
  631. CALL HOME ;move cursor to start of line
  632. MOV DIRTY_BITS,1 ;this will redraw the screen
  633. RET
  634. BOTTOM ENDP
  635. ;=======================================================================
  636. ; This routine moves the cursor to the start of the current line.
  637. ; If <HOME> key and already at start of line, move to start of previous line.
  638. ;-----------------------------------------------------------------------
  639. HOME_KEY PROC NEAR
  640. CALL LEFT ;back up one space, in case at home
  641. HOME_KEY ENDP
  642. HOME PROC NEAR
  643. CALL FIND_START ;find start of line
  644. MOV CURSOR,SI ;save the new cursor
  645. MOV SAVE_COLUMN,0 ;save the cursor column
  646. MOV BYTE PTR CURS_POSN,0 ;store the column number
  647. RET
  648. HOME ENDP
  649. ;=======================================================================
  650. ; These routines move the cursor right and left
  651. ;-----------------------------------------------------------------------
  652. RIGHT PROC NEAR
  653. MOV SI,CURSOR
  654. CMP SI,LAST_CHAR ;at end of file?
  655. JE LR_NO_CHANGE ;if yes, then can't move
  656. ;-----------------------
  657. ; from TEDPLUS
  658. INC SI
  659. CMP SI,LAST_CHAR ;at end of file?
  660. DEC SI
  661. JAE INC_RIGHT ;if yes, then increment
  662. CMP WORD PTR [SI],CRLF ;is it CRLF?
  663. JE MOVE_DOWN ;if yes, then move down to next line
  664. INC_RIGHT:
  665. ;-----------------------
  666. INC CURSOR ;advance the cursor
  667. JMP SHORT LR_RETURN
  668. MOVE_DOWN:
  669. CALL HOME ;move to start of line
  670. JMP SHORT DOWN ;and move down one row
  671. ;(CALL/RETurn)
  672. RIGHT ENDP
  673. ;-----------------------------------------------------------------------
  674. LEFT PROC NEAR
  675. CMP CURSOR,0 ;at start of file?
  676. JZ LR_NO_CHANGE ;then can't move left
  677. MOV DX,CURS_POSN
  678. OR DL,DL ;at first column?
  679. JZ MOVE_UP ;if yes, then move up one
  680. DEC CURSOR ;shift the cursor offset
  681. LR_RETURN:
  682. CALL CURSOR_COL ;compute column for cursor
  683. MOV SAVE_COLUMN,DL ;save the cursor column
  684. LR_NO_CHANGE:
  685. MOV UNDO_LENGTH,0
  686. RET
  687. ;-----------------------
  688. MOVE_UP:
  689. CALL UP ;move up to next row
  690. JMP SHORT ENDD ;and move to end of line
  691. ;(CALL/RETurn)
  692. LEFT ENDP
  693. ;-----------------------------------------------------------------------
  694. ; This routine moves the cursor to the end of the current line.
  695. ; If END key and already at end of line, move to end of next line.
  696. ;-----------------------------------------------------------------------
  697. END_KEY PROC NEAR
  698. CALL RIGHT ;move one space right, if at EOL
  699. END_KEY ENDP
  700. ENDD PROC NEAR
  701. MOV SI,CURSOR
  702. CALL FIND_EOL ;find end of this line
  703. MOV CURSOR,SI ;store the new cursor
  704. CALL CURSOR_COL ;compute the correct column
  705. MOV SAVE_COLUMN,DL ;save the cursor column
  706. RET
  707. ENDD ENDP
  708. ;-----------------------------------------------------------------------
  709. ; This routine moves the cursor down one row.  When the last row is reached, 
  710. ; the screen is shifted up one row.
  711. ;-----------------------------------------------------------------------
  712. DOWN PROC NEAR
  713. MOV UNDO_LENGTH,0
  714. MOV DX,CURS_POSN
  715. CMP DH,ROWS ;at bottom row already?
  716. MOV SI,CURSOR ;get position in file
  717. JE SCREEN_UP ;if at bottom, then scroll up
  718. CALL FIND_NEXT ;find the start of next line
  719. JC DOWN_RET ;if no more lines, then return
  720. MOV CURSOR,SI
  721. INC DH ;advance cursor to next row
  722. CALL SHIFT_RIGHT ;move cursor to current column
  723. DOWN_RET:
  724. RET
  725. ;-----------------------
  726. SCREEN_UP:
  727. CMP SI,LAST_CHAR ;get cursor offset
  728. JE DOWN_RET
  729. CALL FIND_START ;find the start of this line
  730. MOV CURSOR,SI ;this is the new cursor
  731. CALL FIND_NEXT ;find the offset of next line
  732. JC SHIFT_RET ;if no more lines, then return
  733. MOV CURSOR,SI ;this is the new cursor
  734. MOV SI,TOP_OF_SCREEN ;get the start of the top row
  735. CALL FIND_NEXT ;and find the next line
  736. MOV TOP_OF_SCREEN,SI ;store the new top of screen
  737. JMP SHORT SHIFT_RET
  738. ;(CALL/RETurn)
  739. DOWN ENDP
  740. ;-----------------------------------------------------------------------
  741. ; This routine moves the cursor up one row.  If the cursor is at the first row, 
  742. ; the screen is scrolled down.
  743. ;-----------------------------------------------------------------------
  744. UP PROC NEAR
  745. MOV UNDO_LENGTH,0
  746. MOV DX,CURS_POSN
  747. MOV SI,CURSOR
  748. OR DH,DH ;at top row already?
  749. JZ SCREEN_DN ;if yes, then scroll down
  750. DEC DH ;move the cursor up one row
  751. CALL FIND_CR ;find the beginning of this row
  752. MOV CURSOR,SI
  753. CALL FIND_START ;find start of this row
  754. MOV CURSOR,SI
  755. CALL SHIFT_RIGHT ;skip over to current column
  756. AT_TOP:
  757. RET
  758. ;-----------------------
  759. SCREEN_DN:
  760. MOV SI,TOP_OF_SCREEN
  761. OR SI,SI ;at start of file?
  762. JZ AT_TOP ;if at top, then do nothing
  763. CALL FIND_PREVIOUS ;find the preceding line
  764. MOV TOP_OF_SCREEN,SI ;save new top of screen
  765. MOV SI,CURSOR
  766. CALL FIND_PREVIOUS ;find the preceding line
  767. MOV CURSOR,SI ;this is the new cursor
  768. SHIFT_RET:
  769. OR DIRTY_BITS,1 ;need to redraw the screen
  770. MOV SI,CURSOR
  771. MOV DX,CURS_POSN
  772. JMP SHIFT_RIGHT ;move cursor to current column
  773. ;(CALL/RETurn)
  774. UP ENDP
  775. ;=======================================================================
  776. ; These four routines move the screen one page at a time by calling the 
  777. ; UP and DOWN procedures.
  778. ;-----------------------------------------------------------------------
  779. CTRL_PGDN PROC NEAR ;do PgDn then PgUp
  780. CALL PGDN
  781. JMP SHORT PGUP
  782. ;(CALL/RETurn)
  783. CTRL_PGDN ENDP
  784. ;-----------------------------------------------------------------------
  785. PGUP PROC NEAR
  786. MOV CS:PAGE_PROC,OFFSET UP
  787. JMP SHORT PAGE_UP_DN
  788. PGUP ENDP
  789. ;-----------------------------------------------------------------------
  790. CTRL_PGUP PROC NEAR ;do PgUp then PgDn
  791. CALL PGUP
  792. ;** JMP SHORT PGDN
  793. ;(CALL/RETurn)
  794. CTRL_PGUP ENDP
  795. ;-----------------------------------------------------------------------
  796. PGDN PROC NEAR
  797. MOV CS:PAGE_PROC,OFFSET DOWN
  798. PAGE_UP_DN:
  799. MOV CL,CS:ROWS ;get vertical length of screen
  800. SUB CL,5 ;don't page a full screen
  801. XOR CH,CH ;make it a word
  802. PAGE_LOOP:
  803. PUSH CX
  804. CALL PAGE_PROC ;move the cursor down
  805. POP CX
  806. LOOP PAGE_LOOP ;loop for one page length
  807. RET
  808. PGDN ENDP
  809. ;=======================================================================
  810. ; This routine toggles the Insert/Overstrike mode.
  811. ;-----------------------------------------------------------------------
  812. INSERT PROC NEAR
  813. ; ASSUME DS:NOTHING
  814. ;**RO mode NOT CS:INSERT_MODE ;toggle the switch
  815. XOR CS:INSERT_MODE,1 ;toggle the "I/O" switch
  816. CALL REDO_PROMPT ;redraw the insert/overstrike status
  817. RET
  818. INSERT ENDP
  819. ;=======================================================================
  820. ; FILE MANIPULATION services
  821. ;=======================================================================
  822. ; This routine forces the insertion of the NUL character, 00H, in the file.
  823. ;-----------------------------------------------------------------------
  824. NUL_CHAR PROC NEAR
  825. XOR AX,AX
  826. NUL_CHAR ENDP
  827. ;-----------------------------------------------------------------------
  828. ; This routine adds a character into the file.  In insert mode, remaining 
  829. ; characters are pushed forward.  If the scan code for <Enter> is detected, 
  830. ; a <CR><LF> pair is added as the EOL marker.  If the scan code for 
  831. ; <Backspace> is detected, the character to the left of the cursor is 
  832. ; deleted (unless the cursor is already at the start of the file).  
  833. ;-----------------------------------------------------------------------
  834. INSERT_KEY PROC NEAR
  835. ASSUME DS:FILE_SEG
  836. MOV SI,CS:CURSOR
  837. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  838. JA FILE_FULL ;jump if read-only file
  839. CMP AH,28 ;was this the <Enter> key scan code?
  840. JE NEW_LINE ;if yes, make new line: <CR><LF>.
  841. CMP AH,14 ;was it the <Backspace> key scan code?
  842. JE BACK_SPACE ;if yes, delete character left.
  843. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  844. JE INSERT_CHAR ;jump if Insert
  845. ;-----------------------
  846. ; test for overstrike character at end of line or file.
  847. ; if EOL or EOF, then insert rather than overstrike.
  848. ;-----------------------
  849. CMP SI,CS:LAST_CHAR ;at end of file?
  850. JAE INSERT_CHAR
  851. INC SI
  852. CMP SI,CS:LAST_CHAR ;at end of file?
  853. DEC SI
  854. JAE INSERT_CHAR
  855. CMP WORD PTR [SI],CRLF ;at end of line?
  856. JE INSERT_CHAR
  857. OVERSTRIKE_NOT_AT_CRLF:
  858. MOV DI,SI
  859. PUSH AX ;save new character
  860. XCHG DS:[SI],AL ;switch new character for old one
  861. CALL SAVE_CHAR ;store the old character
  862. POP AX ;get back new character
  863. JMP SHORT ADVANCE
  864. ;---------------------------------------
  865. INSERT_CHAR:
  866. PUSH SI
  867. PUSH AX ;save the new character
  868. MOV AX,1
  869. CALL OPEN_SPACE ;make room for it at SI
  870. POP AX ;get back the new character
  871. POP DI
  872. JC FILE_FULL
  873. STOSB ;insert character in file buffer, ES:DI
  874. ADVANCE:
  875. OR CS:DIRTY_BITS,4 ;current line is dirty
  876. ;-----------------------
  877. ; see if we made a CR-LF pair by adding a Ctrl-M with a Ctrl-J
  878. ;-----------------------
  879. CALL C_IF_NEW_CRLF ;see if in middle of new CR-LF
  880. JC FILE_FULL ;jump if new line was done
  881. ;------------------------
  882. CMP AL,CR ;was key <Ctrl-M> - CR?
  883. JNE INS_NOT_CR
  884. MOV CS:DIRTY_BITS,1 ;redraw the screen (just in case EOL)
  885. INS_NOT_CR:
  886. ;-----------------------
  887. PUSH UNDO_LENGTH
  888. CALL RIGHT ;move cursor to next letter
  889. POP UNDO_LENGTH
  890. FILE_FULL:
  891. RET
  892. CR_AT_EOF:
  893. INC CS:CURSOR
  894. RET
  895. ;---------------------------------------
  896. ; process the <Enter> key, make new line
  897. ;---------------------------------------
  898. NEW_LINE:
  899. PUSH SI
  900. MOV AX,2
  901. CALL OPEN_SPACE ;make space for CR and LF
  902. POP DI ;get back old cursor location
  903. JC FILE_FULL
  904. MOV AX,CRLF  ;LF*256+CR
  905. STOSW ;store the CR and LF
  906. JMP SHORT ADVANCE_NEW_LINE ;repaint the screen
  907. ;(CALL/RETurn)
  908. INSERT_KEY ENDP
  909. ;---------------------------------------
  910. ; process the <Backspace> key, delete character left of cursor.
  911. ;---------------------------------------
  912. BACK_SPACE PROC NEAR
  913. OR SI,SI ;is cursor at start of file?
  914. JZ FILE_FULL ;if so, no delete right
  915. CALL LEFT ;move left one space (flush UnDo buffer)
  916. ;**follows JMP DEL_CHAR ;and delete the character (into buffer)
  917. ;(CALL/RETurn)
  918. BACK_SPACE ENDP
  919. ;=======================================================================
  920. ; This routine deletes the character at the cursor by shifting the remaining 
  921. ; characters forward.  <Del> key
  922. ;-----------------------------------------------------------------------
  923. DEL_CHAR PROC NEAR
  924. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  925. JA NO_DEL ;jump if read-only file
  926. MOV CX,LAST_CHAR
  927. MOV SI,CURSOR
  928. MOV DI,SI
  929. CMP SI,CX ;are we at end of file?
  930. JAE NO_DEL ;if yes, then don't delete
  931. LODSB ;loads char in AL, DS:SI
  932. CALL SAVE_CHAR ;save it for UNDO function
  933. MOV AH,[SI] ;look at the next character also
  934. PUSH AX ;save character we're deleting
  935. DEC LAST_CHAR ;shorten the file by one
  936. SUB CX,SI
  937. REP MOVSB ;move file down one, DS:SI to ES:DI
  938. POP AX ;get back character we deleted
  939. CMP AX,CRLF ;did we delete a CR?
  940. JE COMBINE
  941. OR DIRTY_BITS,4 ;current line is dirty
  942. ;-----------------------
  943. ; see if we made a CRLF by deleting a character.
  944. ; if we are in the middle of a CRLF, move the cursor back one.
  945. ;-----------------------
  946. JMP SHORT C_IF_NEW_CRLF
  947. ;(CALL/RETurn) - saves a byte
  948. ;---------------------------------------
  949. COMBINE: ;deleted an EOL marker, CR-LF
  950. CALL DEL_CHAR ;now delete the line feed (recursive)
  951.                 MOV     DIRTY_BITS,3
  952.                 MOV     DX,CURS_POSN
  953. MOV SAVE_COLUMN,DL ;save the cursor column
  954. NO_DEL:
  955. RET
  956. DEL_CHAR ENDP
  957. ;=======================================================================
  958. ; see if we made a CR-LF pair with the cursor located on the LF character 
  959. ; by joining the character (Ctrl-M) with a (Ctrl-J).  If so, back up the 
  960. ; cursor and open a new line and return with carry set.  if not, return with 
  961. ; carry clear.
  962. ;-----------------------------------------------------------------------
  963. C_IF_NEW_CRLF PROC NEAR
  964. MOV SI,CS:CURSOR ;present cursor location
  965. OR SI,SI ;is it at start of file
  966. JZ DONE_CRLF
  967. CMP WORD PTR [SI-1],CRLF ;did we make CR-LF?
  968. JNE DONE_CRLF
  969. DEC CS:CURSOR ;move cursor back to point at CR code
  970. C_IF_NEW_CRLF ENDP
  971. ;---------------------------------------
  972. ; This routine opens a new line.
  973. ;---------------------------------------
  974. ADVANCE_NEW_LINE PROC NEAR ;split line on screen for CR-LF
  975. CALL HOME ;cursor to start of line
  976. CALL DOWN ;move down to the new line
  977. MOV DIRTY_BITS,3 ;repaint the screen and cursor
  978. STC ;C=1 if new line was done
  979. RET
  980. DONE_CRLF:
  981. CLC ;C=0 if not new line
  982. RET
  983. ADVANCE_NEW_LINE ENDP
  984. ;=======================================================================
  985. ; This routine restores any characters which have recently been deleted.
  986. ;-----------------------------------------------------------------------
  987. UNDO PROC NEAR
  988. ; ASSUME DS:FILE_SEG
  989. XOR AX,AX
  990. XCHG AX,CS:UNDO_LENGTH ;get buffer length
  991. MOV SI,OFFSET UNDO_BUFFER
  992. JMP INSERT_STRING
  993. ;(CALL/RETurn)
  994. UNDO ENDP
  995. ;=======================================================================
  996. ; This routine inserts spaces into the file buffer.  On entry, AX
  997. ; contains the number of spaces to be inserted.  On return, CF=1 if 
  998. ; there was not enough space in the file buffer.
  999. ;-----------------------------------------------------------------------
  1000. OPEN_SPACE PROC NEAR
  1001. ; ASSUME DS:FILE_SEG
  1002. MOV CX,LAST_CHAR ;last character in the file
  1003. MOV SI,CX
  1004. MOV DI,CX
  1005. ADD DI,AX ;offset for new end of file
  1006. JC NO_ROOM ;if no more room, return error
  1007. MOV LAST_CHAR,DI ;save offset of end of file
  1008. SUB CX,CURSOR ;number of characters to shift
  1009. DEC DI
  1010. DEC SI
  1011. STD ;string moves goes forward
  1012. REP MOVSB ;shift the file upward
  1013. CLD
  1014. MOV BYTE PTR DIRTY_FILE,0FFH ;file has been altered
  1015. CLC
  1016. NO_ROOM: ;carry is set if no room in file
  1017. RET
  1018. OPEN_SPACE ENDP
  1019. ;=======================================================================
  1020. ; This routine adds a character to the UNDO buffer.
  1021. ;-----------------------------------------------------------------------
  1022. SAVE_CHAR PROC NEAR
  1023. MOV BX,UNDO_LENGTH
  1024. OR BH,BH ;is buffer filled?
  1025. JNZ NO_SAVE ;buffer overflowed, no insert
  1026. INC UNDO_LENGTH
  1027. MOV BYTE PTR CS:UNDO_BUFFER[BX],AL
  1028. MOV BYTE PTR CS:DIRTY_FILE,0FFH ;file altered
  1029. NO_SAVE:
  1030. RET
  1031. SAVE_CHAR ENDP
  1032. ;=======================================================================
  1033. ; This routine deletes from the cursor position to the end of the line.
  1034. ;-----------------------------------------------------------------------
  1035. DEL_EOL PROC NEAR
  1036. ;-----------------------
  1037. ; from TEDPLUS,  modified by JEG, delete line if at column 1.
  1038. ;**Shft-F8 MOV CX,CURSOR_POSN
  1039. ;**Shft-F8 JCXZ DEL_L
  1040. ;-----------------------
  1041. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1042. JA NO_DEL_L ;jump if read-only file
  1043. MOV LINE_FLAG,0
  1044. PUSH CURSOR ;save starting cursor location
  1045. CALL ENDD ;move to the end of the line
  1046. POP SI ;get back starting cursor
  1047. MOV CX,CURSOR ;offset of end of line
  1048. MOV CURSOR,SI ;restore starting cursor
  1049. JMP SHORT DEL_END ;delete characters to end of line
  1050. ;(CALL/RETurn)
  1051. DEL_EOL ENDP
  1052. ;-----------------------------------------------------------------------
  1053. ; This routine deletes a line, placing it in the line buffer. <F9>, <Shft-F8>
  1054. ;-----------------------------------------------------------------------
  1055. DEL_L PROC NEAR
  1056. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1057. JA NO_DEL_L ;jump if read-only file
  1058.   MOV LINE_FLAG,1
  1059. CALL FIND_START ;find start of this line
  1060. MOV CURSOR,SI ;this will be the new cursor
  1061. PUSH SI ;save the cursor position
  1062. CALL FIND_NEXT ;find the next line
  1063. MOV CX,SI ;CX will hold line length
  1064. POP SI ;get back new cursor location
  1065. DEL_END:
  1066. MOV BYTE PTR DIRTY_FILE,0FFH ;file has been altered
  1067. SUB CX,SI ;number of bytes on line
  1068. OR CH,CH ;is line too long to fit?
  1069. JZ NOT_TOO_LONG
  1070. MOV CX,100H ;save only 256 characters
  1071. NOT_TOO_LONG:
  1072. MOV LINE_LENGTH,CX ;store length of deleted line
  1073. JCXZ NO_DEL_L
  1074. MOV DI,OFFSET LINE_BUFFER ;buffer for deleted line
  1075. PUSH CX
  1076. PUSH ES
  1077. PUSH CS
  1078. POP ES ;line buffer is in CSEG
  1079. REP MOVSB ;put deleted line in buffer
  1080. POP ES ;get back file segment
  1081. POP AX
  1082. MOV CX,LAST_CHAR ;get the file size
  1083. SUB LAST_CHAR,AX ;subtract the deleted line
  1084. MOV SI,CURSOR ;get new cursor location
  1085. MOV DI,SI
  1086. ADD SI,AX ;SI points to end of file
  1087. SUB CX,SI ;length of remaining file
  1088. JCXZ NO_DEL_L
  1089. REP MOVSB ;shift remainder of file up
  1090. NO_DEL_L:
  1091. MOV DIRTY_BITS,3 ;redraw the screen and adjust cursor
  1092. RET
  1093. DEL_L ENDP
  1094. ;=======================================================================
  1095. ; This routine undeletes a line by copying it from the line buffer into 
  1096. ; the file.
  1097. ;-----------------------------------------------------------------------
  1098. UDEL_L PROC NEAR
  1099. CMP LINE_FLAG,0 ;is this an end of line only?
  1100. JE UDEL_EOL ;if yes, don't home the cursor
  1101. CALL HOME ;move cursor to home
  1102. UDEL_EOL:
  1103. MOV AX,LINE_LENGTH ;length of deleted line
  1104. MOV SI,OFFSET LINE_BUFFER
  1105. ;**insert_str JMP INSERT_STRING ;(follows immediately)
  1106. ;(CALL/RETurn)
  1107. UDEL_L ENDP
  1108. ;-----------------------------------------------------------------------
  1109. ; This routine inserts AX characters from CS:SI into the file.
  1110. ; (This routine follows "UDEL_L")
  1111. ;-----------------------------------------------------------------------
  1112. INSERT_STRING PROC NEAR
  1113. ; ASSUME DS:FILE_SEG
  1114. PUSH SI ;save string buffer
  1115. MOV SI,CS:CURSOR ;get cursor offset
  1116. PUSH AX ;save length of string
  1117. PUSH SI
  1118. CALL OPEN_SPACE ;make space to insert string
  1119. POP DI ;get back cursor position
  1120. POP CX ;get back string length
  1121. POP SI ;get back string buffer
  1122. JC NO_SPACE ;if no space available, exit
  1123. PUSH DS
  1124. PUSH CS
  1125. POP DS
  1126. ASSUME DS:CSEG
  1127. REP MOVSB ;copy characters DS:SI to ES:DI
  1128. MOV DIRTY_BITS,3 ;redraw the screen and adjust cursor
  1129. POP DS
  1130. ASSUME DS:NOTHING
  1131. CALL C_IF_NEW_CRLF
  1132. NO_SPACE:
  1133. RET
  1134. INSERT_STRING ENDP
  1135. ;=======================================================================
  1136. ; VIDEO services
  1137. ;=======================================================================
  1138. ; This routine displays a character by writing directly to 
  1139. ; the screen buffer.  To avoid screen noise (snow) on the color
  1140. ; card (CGA), the horizontal retrace has to be monitored.
  1141. ;-----------------------------------------------------------------------
  1142. WRITE_INVERSE PROC NEAR
  1143. ASSUME DS:FILE_SEG, ES:FILE_SEG
  1144. MOV BH,CS:INVERSE ;attribute for inverse video
  1145. JMP SHORT WRITE_SCREEN
  1146. ;-----------------------------------------------------------------------
  1147. WRITE_FIND:
  1148. MOV BH,CS:SRCH_CLR ;attribute for find string
  1149. ; MOV BH,CS:INVERSE ;attribute for find string
  1150. JMP SHORT WRITE_SCREEN
  1151. ;-----------------------------------------------------------------------
  1152. WRITE_NORMAL:
  1153. MOV BH,CS:NORMAL ;attribute for normal video
  1154. WRITE_SCREEN:
  1155. MOV BL,AL ;save the character
  1156. PUSH ES
  1157. LES DX,CS:VIDEO_STATUS_REG ;video status register
  1158. ;-------------------------------------------------------
  1159. ; HWAIT is used to "desnow" the display for the CGA.
  1160. ; If not CGA, the following instruction is modified to a 
  1161. ; JMP   SHORT WRITE_IT
  1162. ;-------------------------------------------------------
  1163. HWAIT:
  1164. IN AL,DX ;get video status
  1165. ROR AL,1 ;look at horizontal retrace
  1166. JNC HWAIT ;wait for retrace
  1167. WRITE_IT:
  1168. MOV AX,BX ;get the character/attributes
  1169. STOSW ;write the character
  1170. POP ES
  1171. RET
  1172. WRITE_INVERSE ENDP
  1173. ;=======================================================================
  1174. ; This routine moves the cursor to the row/column in DX.
  1175. ;-----------------------------------------------------------------------
  1176. SET_CURSOR PROC NEAR
  1177. XOR BH,BH ;we're using page zero
  1178. MOV AH,2 ;BIOS set cursor function
  1179. INT 10H
  1180. RET
  1181. SET_CURSOR ENDP
  1182. ;=======================================================================
  1183. ; This routine computes the video buffer offset for the row/column in DX.
  1184. ;-----------------------------------------------------------------------
  1185. POSITION PROC NEAR
  1186. MOV AX,CS:COLUMNS ;take columns per row
  1187. MUL DH ;times row number
  1188. XOR DH,DH
  1189. ADD AX,DX ;add the column number
  1190. SHL AX,1 ;times 2 for offset
  1191. MOV DI,AX ;return result in DI
  1192. RET
  1193. POSITION ENDP
  1194. ;=======================================================================
  1195. ; This routine erases from the location in DX to the right edge of the screen.
  1196. ;-----------------------------------------------------------------------
  1197. ERASE_EOL PROC NEAR
  1198. ASSUME DS:NOTHING
  1199. CALL POSITION ;find screen offset
  1200. MOV CX,CS:COLUMNS ;get screen size
  1201. SUB CL,DL ;subtract current position
  1202. JCXZ NO_CLEAR
  1203. ERASE_LOOP:
  1204. MOV AL," " ;write blanks to erase
  1205. CALL WRITE_NORMAL ;display it
  1206. LOOP ERASE_LOOP
  1207. NO_CLEAR:
  1208. RET
  1209. ERASE_EOL ENDP
  1210. ;=======================================================================
  1211. ; This routine displays the function key prompt and insert/overstrike mode 
  1212. ; state.  It sets DIRTY_BITS := 3 to force redraw of the entire screen 
  1213. ; and locate cursor.
  1214. ;-----------------------------------------------------------------------
  1215. REDO_PROMPT PROC NEAR
  1216. ASSUME DS:NOTHING, ES:NOTHING
  1217. PUSH DS
  1218. PUSH CS
  1219. POP DS
  1220. ASSUME DS:CSEG
  1221. MOV DH,ROWS ;put prompt at last row
  1222. INC DH
  1223. XOR DL,DL ;and column 0
  1224. CALL POSITION ;convert to screen offset
  1225. MOV SI,OFFSET PROMPT_STRING
  1226. KEY_LOOP:
  1227. MOV AL,"F" ;display an "F"
  1228. CALL WRITE_NORMAL
  1229. LODSB
  1230. OR AL,AL ;last key in prompt?
  1231. JZ PROMPT_DONE
  1232. CALL WRITE_NORMAL
  1233. CMP BYTE PTR CS:[SI],"0" ;is it F10?
  1234. JNE TEXT_LOOP
  1235. LODSB
  1236. CALL WRITE_NORMAL
  1237. TEXT_LOOP:
  1238. LODSB
  1239. OR AL,AL ;last letter in word?
  1240. JNZ WRITE_CHAR
  1241. MOV AL," " ;display a space
  1242. CALL WRITE_NORMAL
  1243. JMP KEY_LOOP
  1244. WRITE_CHAR:
  1245. CALL WRITE_INVERSE ;display the letter
  1246. JMP TEXT_LOOP ;do the next letter
  1247. PROMPT_DONE:
  1248. MOV DH,ROWS
  1249. INC DH ;get the last row on the screen
  1250. MOV DL,PROMPT_LENGTH + 9
  1251. CALL ERASE_EOL ;erase to the end of this row
  1252. MOV BL,INSERT_MODE
  1253. XOR BH,BH
  1254. MOV AL,CS:[BX + OFFSET INSERT_CODE]
  1255. ; MOV AL,"O" ;write an "O" (for "Overstrike")
  1256. ; CMP INSERT_MODE,1 ;in insert mode?
  1257. ; JB OVERSTRIKE
  1258. ; MOV AL,"I" ;write an "I" (for "Insert")
  1259. ; JE OVERSTRIKE
  1260. ; MOV AL,"R" ;write an "R" (for "read-only")
  1261. OVERSTRIKE:
  1262. DEC DI ;backup one character position
  1263. DEC DI
  1264. CALL WRITE_NORMAL
  1265. MOV DIRTY_BITS,3 ;now redraw the entire screen
  1266. POP DS
  1267. ASSUME DS:NOTHING
  1268. RET
  1269. REDO_PROMPT ENDP
  1270. ;=======================================================================
  1271. ; This routine displays the file buffer on the screen.
  1272. ; DISPLAY_BOTTOM has been deleted to reduce the program code size.
  1273. ;-----------------------------------------------------------------------
  1274. DISPLAY_SCREEN PROC NEAR
  1275. ASSUME DS:FILE_SEG, ES:FILE_SEG
  1276.                 TEST    DIRTY_BITS,2    ;see if we should adjust the cursor
  1277. JZ DISP_CURS_OK
  1278. MOV SI,CURSOR ;get the new cursor offset
  1279. MOV DX,CURS_POSN ;also get the current row
  1280. CALL LOCATE ;adjust the cursor screen position
  1281. DISP_CURS_OK:
  1282.                 MOV     DX,CURS_POSN
  1283. MOV SAVE_ROW,DH
  1284. CALL SET_CURSOR ;position the cursor
  1285.                 TEST    DIRTY_BITS,1    ;see if we should update the screen
  1286.                 JNZ     DO_UPDATE_SCREEN
  1287.                 TEST    DIRTY_BITS,4    ;is the current line dirty?
  1288.                 JZ      DISP_DONE       ;if not, take jump
  1289.                 CALL    DISPLAY_CURRENT ;redraw the current line
  1290.                 JMP     SHORT DISP_DONE
  1291. DO_UPDATE_SCREEN:
  1292.                 MOV     SI,TOP_OF_SCREEN ;point to first char on screen
  1293. XOR DH,DH ;start at first row
  1294. ; JMP SHORT NEXT_ROW
  1295. ; ;-----------------------
  1296. ;DISPLAY_BOTTOM: ;this redraws the bottom only
  1297. ; CALL FIND_START ;find first character on this row
  1298. ; MOV DX,CURS_POSN ;get current cursor row
  1299. NEXT_ROW:
  1300. PUSH DX
  1301. CALL DISPLAY_LINE ;display a line
  1302. POP DX
  1303. ;-----------------------
  1304. ; the keyboard is tested here to see if a key is waiting
  1305. ;-----------------------
  1306. MOV AH,1
  1307. INT 16H
  1308. MOV AL,1 ;for dirty_bits, update not completed
  1309. JNZ DISP_NOT_DONE ;jump if there is a key is waiting
  1310. INC DH ;move to the next row
  1311. CMP DH,ROWS ;at end of screen yet?
  1312. JBE NEXT_ROW ;do all the rows
  1313. DISP_DONE:
  1314.                 MOV     AL,0
  1315. DISP_NOT_DONE:
  1316.                 MOV     DIRTY_BITS,AL   ;screen is completely redone
  1317. RET
  1318. DISPLAY_SCREEN ENDP
  1319. ;=======================================================================
  1320. ; This routine displays a single line to the screen.  DH holds the 
  1321. ; row number, SI has the offset into the file buffer.  Tabs are expanded.  
  1322. ; Adjustment is made for side shift.
  1323. ;-----------------------------------------------------------------------
  1324. DISPLAY_CURRENT PROC NEAR
  1325. ; ASSUME DS:FILE_SEG
  1326. CALL FIND_START
  1327. MOV DX,CS:CURS_POSN
  1328. DISPLAY_CURRENT ENDP
  1329. ;-----------------------
  1330. DISPLAY_LINE PROC NEAR ;external entry point
  1331. XOR DL,DL ;start at column zero
  1332. MOV CS:MARGIN_COUNT,DL
  1333. MOV CX,DX ;use CL to count the columns
  1334. CALL POSITION ;compute offset into video
  1335. NEXT_CHAR:
  1336. CMP SI,LAST_CHAR ;at end of file?
  1337. JAE LINE_DONE
  1338. LODSB ;get next character, DS:SI
  1339. CMP AL,TAB ;is this a Tab character?
  1340. JE EXPAND_TAB ;if yes, expand to spaces
  1341. CMP SI,LAST_CHAR ;at end of file now?
  1342. JAE DO_PUT ;jump, can't be CR-LF pair
  1343. CMP WORD PTR [SI-1],CRLF ;EOL marker
  1344. JE FOUND_CR ;quit when a CR-LF is found
  1345. DO_PUT:
  1346. CALL PUT_CHAR ;put character onto screen
  1347. TAB_DONE:
  1348. CMP CL,CS:COLUMNSB ;at right edge of screen?
  1349. JB NEXT_CHAR
  1350. ;-----------------------
  1351. ; from TEDPLUS
  1352. INC SI
  1353. CMP SI,LAST_CHAR ;at end of file?
  1354. DEC SI
  1355. JAE NOT_BEYOND
  1356. CMP WORD PTR [SI],CRLF ;at end of line?
  1357. ;----------------------
  1358. JE NOT_BEYOND
  1359. DO_DIAMOND:
  1360. DEC DI ;backup one character
  1361. DEC DI
  1362. MOV AL,4 ;show a diamond
  1363. CALL WRITE_INVERSE ;in inverse video
  1364. NOT_BEYOND:
  1365. JMP FIND_NEXT ;find start of next line
  1366. ;(CALL/RETurn)
  1367. ;---------------------------------------
  1368. EXPAND_TAB:
  1369. MOV AL," " ;convert tab to spaces
  1370. CALL PUT_CHAR
  1371. MOV AL,MARGIN_COUNT
  1372. ADD AL,CL ;CL is column count
  1373. TEST AL,00000111B ;at even multiples of eight?
  1374. JNZ EXPAND_TAB ;if not, keep adding spaces
  1375. JMP TAB_DONE
  1376. ;---------------------------------------
  1377. FOUND_CR:
  1378. INC SI ;past the CR-LF
  1379. LINE_DONE:
  1380. MOV DX,CX
  1381. JMP ERASE_EOL ;erase the end of the line
  1382. ;(CALL/RETurn)
  1383. ;-----------------------
  1384. DISPLAY_LINE ENDP
  1385. ;=======================================================================
  1386. ; This routine displays a single character to the screen.  If the character 
  1387. ; is marked, it is shown in inverse video.  Characters outside the current 
  1388. ; margin are not displayed.  Characters left of the margin are skipped.
  1389. ;-----------------------------------------------------------------------
  1390. PUT_CHAR PROC NEAR
  1391. ; ASSUME DS:FILE_SEG
  1392. MOV BL,MARGIN_COUNT ;get distance to left margin
  1393. CMP BL,LEFT_MARGIN ;are we inside left margin?
  1394. JAE IN_WINDOW ;yes, show the character
  1395. INC BL
  1396. MOV MARGIN_COUNT,BL
  1397. RET
  1398. ;-----------------------
  1399. ; from TEDPLUS
  1400. IN_WINDOW:
  1401. CMP SRCH_FLG,0
  1402. JE CKM
  1403. CMP SI,SRCH_BASE
  1404. JBE CKM
  1405. CMP SI,SRCH_END
  1406. JA CKM
  1407. CALL WRITE_FIND
  1408. ;**inverse CALL WRITE_INVERSE ;found string highlighted, inverse video
  1409. JMP SHORT NEXT_COL
  1410. CKM:
  1411. ;-----------------------
  1412. CMP SI,MARK_START ;is this character marked?
  1413. JBE NOT_MARKED
  1414. CMP SI,MARK_END
  1415. JA NOT_MARKED
  1416. CALL WRITE_INVERSE ;marked characters shown inverse
  1417. JMP SHORT NEXT_COL
  1418. ;-----------------------
  1419. NOT_MARKED:
  1420. CALL WRITE_NORMAL
  1421. NEXT_COL:
  1422. INC CL ;increment the column count
  1423. RET
  1424. PUT_CHAR ENDP
  1425. ;=======================================================================
  1426. ; This routine adjusts the cursor position ahead to the saved cursor column.  
  1427. ; On entry DH has the cursor row.
  1428. ;-----------------------------------------------------------------------
  1429. SHIFT_RIGHT PROC NEAR
  1430. ; ASSUME DS:FILE_SEG
  1431. MOV CL,SAVE_COLUMN ;keep the saved cursor offset
  1432. XOR CH,CH
  1433. MOV BP,CX ;keep the saved cursor position
  1434. ADD CL,LEFT_MARGIN ;shift into visible window
  1435. ADC CH,0
  1436. XOR DL,DL
  1437. MOV CURS_POSN,DX ;get cursor row/column
  1438. JCXZ NO_CHANGE
  1439. RIGHT_AGAIN:
  1440. PUSH CX
  1441. ;-----------------------
  1442. ; (JEG)
  1443. INC SI
  1444. CMP SI,LAST_CHAR ;at end of file?
  1445. DEC SI
  1446. JAE DO_MOVE
  1447. CMP WORD PTR [SI],CRLF ;at end of line?
  1448. ;-----------------------
  1449. JE DONT_MOVE ;if at end, stop moving
  1450. DO_MOVE:
  1451. CALL RIGHT ;move right one character
  1452. DONT_MOVE:
  1453. POP CX
  1454. MOV AL,SAVE_COLUMN
  1455. XOR AH,AH
  1456. CMP AX,CX ;is cursor still in margin?
  1457. JL IN_MARGIN ;if yes, keep moving
  1458. MOV DX,CURS_POSN ;get cursor column again
  1459. XOR DH,DH
  1460. CMP DX,BP ;at saved cursor position?
  1461. JE RIGHT_DONE ;if yes, we're done
  1462. JA RIGHT_TOO_FAR ;did we go too far?
  1463. IN_MARGIN:
  1464. LOOP RIGHT_AGAIN
  1465. RIGHT_DONE:
  1466. MOV CX,BP
  1467. MOV SAVE_COLUMN,CL ;get back saved cursor position
  1468. NO_CHANGE:
  1469. RET
  1470. ;-----------------------
  1471. RIGHT_TOO_FAR:
  1472. CALL LEFT ;move back left one place
  1473. MOV CX,BP
  1474. MOV SAVE_COLUMN,CL ;get back saved cursor position
  1475. RET
  1476. SHIFT_RIGHT ENDP
  1477. ;=======================================================================
  1478. ; This routine finds the beginning of the previous line.
  1479. ;-----------------------------------------------------------------------
  1480. FIND_PREVIOUS PROC NEAR
  1481. ; ASSUME DS:FILE_SEG
  1482. PUSH CURSOR ;save the cursor location
  1483. CALL FIND_CR ;find the start of this line
  1484. MOV CURSOR,SI ;save the new cursor
  1485. CALL FIND_START ;find the start of this line
  1486. POP CURSOR ;get back starting cursor
  1487. RET
  1488. FIND_PREVIOUS ENDP
  1489. ;=======================================================================
  1490. ; This routine searches for the previous carriage return.  
  1491. ; Search starts at DS:SI.
  1492. ;-----------------------------------------------------------------------
  1493. FIND_CR PROC NEAR
  1494. ; ASSUME DS:FILE_SEG
  1495. PUSH CX
  1496. MOV AL,LF ;look for a line feed character
  1497. MOV DI,SI
  1498. MOV CX,SI
  1499. JCXZ AT_BEGINNING
  1500. DEC DI
  1501. STD ;search backwards
  1502. LF_PREV:
  1503. REPNE SCASB ;scan for the character
  1504. ;-----------------------
  1505. ; from TEDPLUS
  1506. JCXZ LF_END
  1507. CMP BYTE PTR [DI],CR
  1508. JNE LF_PREV
  1509. DEC DI
  1510. LF_END:
  1511. ;-----------------------
  1512. CLD ;restore the direction flag
  1513. INC DI
  1514. MOV SI,DI
  1515. AT_BEGINNING:
  1516. POP CX
  1517. RET
  1518. FIND_CR ENDP
  1519. ;=======================================================================
  1520. ; This routine skips past the CR and LF at SI.  SI returns new offset.
  1521. ;-----------------------------------------------------------------------
  1522. SKIP_CR_LF PROC NEAR
  1523. ; ASSUME CS:FILE_SEG
  1524. CMP SI,LAST_CHAR ;at last char in file?
  1525. JAE NO_SKIP ;if yes, don't skip anything
  1526. CMP BYTE PTR [SI],CR ;is first character a CR?
  1527. JNE NO_SKIP
  1528. INC SI ;look at next character
  1529. CMP SI,LAST_CHAR ;is it at the end of file?
  1530. JAE NO_SKIP ;if yes, don't skip anymore
  1531. CMP BYTE PTR [SI],LF ;is next character a line feed?
  1532. JNE NO_SKIP ;skip any line feeds also
  1533. INC SI
  1534. NO_SKIP:
  1535. RET
  1536. SKIP_CR_LF ENDP
  1537. ;=======================================================================
  1538. ; This routine computes the location of the start of current line.  
  1539. ; Returns SI pointing to the first character of the current line.  
  1540. ;-----------------------------------------------------------------------
  1541. FIND_START PROC NEAR
  1542. ; ASSUME DS:FILE_SEG
  1543. MOV SI,CURSOR ;get the current cursor
  1544. OR SI,SI ;at start of file?
  1545. JZ AT_START ;if yse, we're done
  1546. CALL FIND_CR ;find the CR
  1547. CALL SKIP_CR_LF
  1548. AT_START:
  1549. RET
  1550. FIND_START ENDP
  1551. ;=======================================================================
  1552. ; This routine finds the offset of the start of the next line.  The search 
  1553. ; is started at location of ES:SI.  On return, CF=1 if no CR was found.
  1554. ;-----------------------------------------------------------------------
  1555. FIND_NEXT PROC NEAR
  1556. ; ASSUME DS:FILE_SEG
  1557. PUSH CX
  1558. CALL FIND_EOL ;find the end of this line
  1559. JC AT_NEXT ;if at end of file, return
  1560. CALL SKIP_CR_LF ;skip past CR and LF
  1561. CLC ;indicate end of line found
  1562. AT_NEXT:
  1563. POP CX
  1564. RET
  1565. FIND_NEXT ENDP
  1566. ;=======================================================================
  1567. ; This routine searches for the next carriage return in the file.  
  1568. ; The search starts at the offset in register SI.  
  1569. ;-----------------------------------------------------------------------
  1570. FIND_EOL PROC NEAR
  1571. ; ASSUME DS:FILE_SEG
  1572. MOV AL,CR ;look for a carriage return
  1573. CR_SCAN:
  1574. MOV CX,LAST_CHAR ;last letter in the file
  1575. SUB CX,SI ;count for the search
  1576. MOV DI,SI
  1577. JCXZ AT_END ;if nothing to search, return
  1578. REPNE SCASB ;scan for the character
  1579. MOV SI,DI ;return the location of the CR
  1580. JCXZ AT_END ;if not found, return
  1581. ;-----------------------
  1582. ; from TEDPLUS
  1583. CMP BYTE PTR [SI],LF
  1584. JNE CR_SCAN
  1585. ;-----------------------
  1586. DEC SI ;back up one, to CR character
  1587. CLC ;indicate the CR was found
  1588. RET
  1589. AT_END:
  1590. STC ;indicate CR was not found
  1591. RET
  1592. FIND_EOL ENDP
  1593. ;=======================================================================
  1594. ; This routine positions the screen with the cursor at the row 
  1595. ; selected in register DH.  On entry, SI holds the cursor offset.
  1596. ;-----------------------------------------------------------------------
  1597. LOCATE PROC NEAR
  1598. ; ASSUME DS:FILE_SEG
  1599. MOV CL,DH
  1600. XOR CH,CH
  1601. MOV CURSOR,SI
  1602. XOR DX,DX ;start at top of screen
  1603. OR SI,SI ;at start of buffer?
  1604. JZ LOCATE_FIRST
  1605. CALL FIND_START ;get start of this row
  1606. XOR DX,DX ;start at top of screen
  1607. OR SI,SI ;is cursor at top of file?
  1608. JZ LOCATE_FIRST
  1609. JCXZ LOCATE_FIRST ;if location to top row were done
  1610. FIND_TOP:
  1611. PUSH SI
  1612. PUSH CX
  1613. CALL FIND_CR ;find previous row
  1614. POP CX
  1615. POP AX
  1616. CMP WORD PTR [SI],CRLF
  1617. JNE LOCATE_FIRST
  1618. CMP SI,AX ;did it change?
  1619. JE LOCATE_DONE ;if not, quit moving
  1620. INC DH ;cursor moves to next row
  1621. LOOP FIND_TOP
  1622. LOCATE_DONE:
  1623. PUSH CURSOR
  1624. MOV CURSOR,SI
  1625. CALL FIND_START ;find start at top of screen
  1626. POP CURSOR
  1627. LOCATE_FIRST:
  1628. MOV TOP_OF_SCREEN,SI
  1629. MOV CURS_POSN,DX
  1630. CALL CURSOR_COL
  1631. MOV SAVE_COLUMN,DL
  1632. RET
  1633. LOCATE ENDP
  1634. ;=======================================================================
  1635. ; This routine computes the correct column for the cursor.  No inputs.  
  1636. ; On exit, CURS_POSN is set and DX has row/column.
  1637. ;-----------------------------------------------------------------------
  1638. CURSOR_COL PROC NEAR
  1639. ; ASSUME DS:FILE_SEG
  1640. MOV SI,CURSOR ;get cursor offset
  1641. CALL FIND_START ;find start of this line
  1642. MOV CX,CURSOR ;cursor location in file
  1643. SUB CX,SI
  1644. MOV DX,CURS_POSN ;get current row
  1645. XOR DL,DL ;start at column zero
  1646. MOV MARGIN_COUNT,DL ;count past the left margin
  1647. JCXZ COL_DONE
  1648. CURSOR_LOOP:
  1649. LODSB ;get the next character
  1650. INC SI
  1651. CMP SI,LAST_CHAR
  1652. DEC SI
  1653. JAE NOT_EOL ;is <CR> without <LF>, at end of file
  1654. CMP WORD PTR [SI-1],CRLF ;(JEG)
  1655. JE COL_DONE ;if at end, we're done
  1656. NOT_EOL:
  1657. CMP AL,TAB ;is it a tab?
  1658. JNE NOT_A_TAB
  1659. MOV BL,MARGIN_COUNT
  1660. OR BL,00000111B
  1661. MOV MARGIN_COUNT,BL
  1662. CMP BL,LEFT_MARGIN ;inside visible window yet?
  1663. JB NOT_A_TAB ;if not, don't advance cursor
  1664. OR DL,00000111B ;move to multiple of eight
  1665. NOT_A_TAB:
  1666. MOV BL,MARGIN_COUNT
  1667. INC BL
  1668. MOV MARGIN_COUNT,BL
  1669. CMP BL,LEFT_MARGIN
  1670. JBE OUT_OF_WINDOW
  1671. INC DL ;we're at next column now
  1672. OUT_OF_WINDOW:
  1673. LOOP CURSOR_LOOP
  1674. COL_DONE:
  1675. CMP DL,COLUMNSB ;past end of display?
  1676. JB COLUMN_OK ;if not, we're OK
  1677. MOV DL,COLUMNSB
  1678. DEC DL ;leave cursor at last column
  1679. COLUMN_OK:
  1680. MOV CURS_POSN,DX ;store at last column
  1681. RET
  1682. CURSOR_COL ENDP
  1683. ;=======================================================================
  1684. ; MARK, CUT, PASTE, PRINT services
  1685. ;=======================================================================
  1686. ; This routine toggles the mark state and resets the paste buffer pointers.
  1687. ;-----------------------------------------------------------------------
  1688. MARK PROC NEAR
  1689. XOR AX,AX
  1690. NOT CS:MARK_MODE ;toggle the mode flag
  1691. CMP CS:MARK_MODE,AL ;turning mode ON?
  1692. JNE MARK_ON
  1693. OR CS:DIRTY_BITS,1 ;need to redraw the screen
  1694. MOV CS:MARK_START,0FFFFH
  1695. JMP SHORT MARK_RET
  1696. ;-----------------------
  1697. MARK_ON:
  1698. MOV AX,CS:CURSOR ;get the cursor offset
  1699. MOV CS:MARK_START,AX ;start of marked range
  1700. MARK_RET:
  1701. MOV CS:MARK_END,AX ;end of marked range
  1702. MOV CS:MARK_HOME,AX ;center of marked range
  1703. RET
  1704. MARK ENDP
  1705. ;=======================================================================
  1706. ; This routine removes the marked text and places it in the paste buffer.
  1707. ;-----------------------------------------------------------------------
  1708. CUT PROC NEAR
  1709. CMP CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1710. JA NO_MARK ;jump if read-only file
  1711. CMP CS:MARK_MODE,0 ;is the mark mode on?
  1712. JE NO_MARK ;if not, then do nothing
  1713. MOV CX,CS:MARK_END ;get end of mark region
  1714. MOV SI,CS:MARK_START ;get start of mark region
  1715. SUB CX,SI ;number of bytes selected
  1716. MOV PASTE_SIZE,CX
  1717. XOR DI,DI ;point to paste buffer
  1718. PUSH CX
  1719. PUSH ES
  1720. MOV ES,CS:PASTE_SEG ;set the paste buffer segment to ES
  1721. REP MOVSB ;deleted text to buffer, DS:SI to ES:DI
  1722. POP ES
  1723. POP AX
  1724. MOV CX,CS:LAST_CHAR
  1725. SUB CS:LAST_CHAR,AX ;shorten the file this much
  1726. MOV DI,CS:MARK_START
  1727. MOV SI,CS:MARK_END
  1728. SUB CX,SI
  1729. JCXZ NO_DELETE
  1730. REP MOVSB ;shorten the file, DS:SI to ES:DI
  1731. NO_DELETE:
  1732. MOV DX,CS:CURS_POSN
  1733. MOV SI,CS:MARK_START
  1734. CALL LOCATE ;adjust the screen position
  1735. CALL MARK ;this turns off select
  1736. ;-----------------------
  1737. ; see if we made a CR-LF pair by cutting the character(s) from
  1738. ; between a Ctrl-M and a Ctrl-J.  If so, open a new line.
  1739. ;-----------------------
  1740. CALL C_IF_NEW_CRLF
  1741. NO_MARK:
  1742. RET
  1743. CUT ENDP
  1744. ;=======================================================================
  1745. ; This routine copies the paste buffer into the file at the cursor location.
  1746. ;-----------------------------------------------------------------------
  1747. PASTE PROC NEAR
  1748. MOV AX,PASTE_SIZE ;number of characters in buffer
  1749. OR AX,AX ;any there?
  1750. JZ NO_PASTE ;if not, nothing to paste
  1751. MOV SI,CURSOR ;get cursor location
  1752. PUSH AX
  1753. PUSH SI
  1754. CALL OPEN_SPACE ;make room for new characters
  1755. POP DI
  1756. POP CX
  1757. JC NO_PASTE ;if no room, just exit
  1758. XOR SI,SI ;point to start of paste buffer
  1759. PUSH DS
  1760. MOV DS,PASTE_SEG ;segment of paste buffer
  1761. REP MOVSB ;copy in the new characters
  1762. POP DS
  1763. OR DIRTY_BITS,1 ;redraw the screen
  1764. CALL C_IF_NEW_CRLF
  1765. NO_PASTE:
  1766. RET
  1767. PASTE ENDP
  1768. ;=======================================================================
  1769. ; This routine prints an ASCII Form-Feed character.
  1770. ;-----------------------------------------------------------------------
  1771. PRINT_FF PROC NEAR
  1772. CALL MARK ;toggle MARK "on"
  1773. PUSH DS
  1774. PUSH CS
  1775. POP DS
  1776. MOV CX,1 ;one character to print
  1777. MOV SI,OFFSET FF ;offset of last byte in paste buffer
  1778. CALL DO_FF_CHAR
  1779. POP DS
  1780. RET
  1781. FF DB 12 ;the ASCII Form-Feed character
  1782. PRINT_FF ENDP
  1783. ;-----------------------------------------------------------------------
  1784. ; This routine prints the marked text.  If printer fails, it is cancelled.
  1785. ;-----------------------------------------------------------------------
  1786. PRINT PROC NEAR
  1787. CMP MARK_MODE,0 ;is mark mode on?
  1788. JE PRINT_RET ;if not, nothing to print
  1789. MOV CX,MARK_END ;end of marked region
  1790. MOV SI,MARK_START ;start of marked region
  1791. SUB CX,SI ;number of bytes selected
  1792. JCXZ PRINT_DONE ;if nothing to print, return
  1793. DO_FF_CHAR:
  1794. XOR DX,DX ;select printer 0
  1795. MOV AH,2
  1796. INT 17H ;get printer status
  1797. TEST AH,10000000B ;is busy bit set?
  1798. JZ PRINT_DONE
  1799. TEST AH,00100000B ;is printer out of paper?
  1800. JNZ PRINT_DONE
  1801. PRINT_LOOP:
  1802. LODSB
  1803. XOR AH,AH
  1804. INT 17H ;print the character
  1805. ROR AH,1 ;check the time out bit
  1806. JC PRINT_DONE ;if set, quit printing
  1807. LOOP PRINT_LOOP
  1808. MOV AL,CR
  1809. ;------ [typographical error in article]
  1810. ;**nop! XOR AH,0 ;[would be No-Operation]
  1811. XOR AH,AH
  1812. ;------
  1813. INT 17H ;finish with a CR
  1814. PRINT_DONE:
  1815. CALL MARK ;turn off the mark status
  1816. PRINT_RET:
  1817. RET
  1818. PRINT ENDP
  1819. ;=======================================================================
  1820. ; CHARACTER STRING SEARCH and SEARCH AGAIN services; HELP screen
  1821. ;=======================================================================
  1822. ; from TEDPLUS
  1823. ; This routine is used to search or search again for a character string.
  1824. ;-----------------------------------------------------------------------
  1825. FIND_STR PROC NEAR
  1826. PUSH DS
  1827. MOV BX,CS
  1828. MOV DS,BX
  1829. ASSUME DS:CSEG
  1830. ;---------------------------------------
  1831. ;** now ShftF6 CMP AH,66H ;Is it shift F9
  1832. CMP AH,89 ;Is it shift-F6 (JEG)
  1833. ;---------------------------------------
  1834. JE RPT_FIND
  1835. MOV DH,ROWS
  1836. INC DH ;Last row on the screen
  1837. XOR DL,DL ;First column
  1838. MOV SI,OFFSET SRCH_PROMPT
  1839. CALL TTY_STRING ;Display search prompt
  1840. MOV DX, OFFSET SRCH_MAX
  1841. MOV AH,0AH
  1842. INT 21H ;Read input string
  1843. RPT_FIND:
  1844. XOR DX,DX
  1845. MOV DL,BYTE PTR SRCH_SIZ
  1846. ADD DX,OFFSET SRCH_STR
  1847. MOV DI,DX
  1848. DEC DI
  1849. MOV SRCH_END,DI
  1850. XOR DX,DX
  1851. MOV SI,CURSOR
  1852. INC SI
  1853. MOV SRCH_BASE,SI
  1854. S_REDO:
  1855. MOV DI,OFFSET SRCH_STR
  1856. MOV BX,SRCH_BASE
  1857. S_CYCLE: MOV AL,[DI]
  1858. MOV AH,AL ;CONVERT AL TO OPPOSITE AND PUT IN AH
  1859. CMP AL,'A'
  1860. JB S_CMP
  1861. CMP AL,'Z'
  1862. JA TSTLO
  1863. XOR AH,20H ;toggle letter case
  1864. JMP SHORT S_CMP
  1865. TSTLO: CMP AL,'a'
  1866. JB S_CMP
  1867. CMP AL,'z'
  1868. JA S_CMP
  1869. XOR AH,20H ;toggle letter case
  1870. S_CMP: CMP BX,LAST_CHAR
  1871. JA END_MCH
  1872. CMP AL,ES:[BX]
  1873. JE S_MCH
  1874. CMP AH,ES:[BX]
  1875. JE S_MCH
  1876. CMP DI,OFFSET SRCH_STR
  1877. JNE S_REDO
  1878. INC BX
  1879. CMP WORD PTR ES:[BX-1],CRLF ;test for EOL marker
  1880. JNE S_BX1
  1881. INC DL
  1882. S_BX1: JMP SHORT S_CMP
  1883. S_MCH: INC BX
  1884. CMP DI,OFFSET SRCH_STR
  1885. JNE NO_BSE
  1886. MOV SRCH_BASE,BX
  1887. NO_BSE: ADD DH,DL
  1888. XOR DL,DL
  1889. CMP DI,SRCH_END
  1890. JE YEA_MCH
  1891. INC DI
  1892. JMP SHORT S_CYCLE
  1893. YEA_MCH:
  1894. MOV SRCH_FLG,1
  1895. MOV SI,SRCH_BASE
  1896. DEC SI
  1897. MOV SRCH_BASE,SI
  1898. MOV CURSOR,SI
  1899. XOR BX,BX
  1900. MOV BL,BYTE PTR SRCH_SIZ
  1901. ADD BX,SI
  1902. MOV SRCH_END,BX
  1903. XOR DL,DL
  1904. ADD DX,CURS_POSN
  1905. CMP DH,ROWS
  1906. JBE NEW_S
  1907. XOR DX,DX
  1908. NEW_S:
  1909. POP DS ;ASSUME is no longer valid
  1910. CALL LOCATE
  1911.                 JMP     SHORT END_MCH2
  1912. END_MCH:                
  1913. POP DS
  1914. END_MCH2:
  1915.                 CALL    REDO_PROMPT     ;redraw the prompt and the screen
  1916. RET
  1917. FIND_STR ENDP
  1918. ;=======================================================================
  1919. ; This routine displays a user help screen
  1920. ;-----------------------------------------------------------------------
  1921. HELP PROC NEAR
  1922. PUSH DS
  1923. PUSH CS
  1924. POP DS
  1925. ASSUME DS:CSEG ;for func-9, display message
  1926. CALL CLR_SCREEN
  1927. MOV DX,OFFSET HELP_SCREEN ;message is at DS:DX in CSEG
  1928. MOV AH,9 ;display message
  1929. INT 21H
  1930. HELP_WAIT_KEY:
  1931. MOV AH,1 ;wait for any key pressed
  1932. INT 16H
  1933. JZ HELP_WAIT_KEY
  1934. MOV AH,0
  1935. INT 16H
  1936. POP DS
  1937. ASSUME DS:NOTHING
  1938. JMP REDO_PROMPT ;redraw the prompt and the screen
  1939. ;(CALL/RETurn)
  1940. HELP ENDP
  1941. ;=======================================================================
  1942. ; This routine prompts for a filename then writes the file.  The original 
  1943. ; file is renamed to filename.BAK.  If an invalid filename is entered, the 
  1944. ; speaker is beeped.  If the file has not been altered, the edit file is 
  1945. ; abandoned and control is immediately returned to DOS.  
  1946. ;-----------------------------------------------------------------------
  1947. EXIT PROC NEAR
  1948. PUSH DS ;save in case ESC key
  1949. PUSH ES
  1950. MOV AX,CS
  1951. MOV DS,AX
  1952. MOV ES,AX
  1953. ASSUME DS:CSEG, ES:CSEG
  1954. TEST BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
  1955. JNZ NEXT_LETTER ;(jump was out of range)
  1956. JMP FINISHED ;file has not been altered, no save.
  1957. ;-----------------------
  1958. IS_BACKSPACE:
  1959. CMP DI,NAME_POINTER ;at first letter?
  1960. JLE NEXT_LETTER ;if yes, don't erase it
  1961. MOV BYTE PTR [DI-1],0
  1962. DEC NAME_END
  1963. NEXT_LETTER:
  1964. MOV DH,ROWS
  1965. INC DH ;last row on the screen
  1966. XOR DL,DL ;first column
  1967. MOV SI,OFFSET SAVE_MESS
  1968. PUSH DX
  1969. CALL TTY_STRING ;display a prompt
  1970. POP DX
  1971. ADD DL,9 ;move right 9 spaces
  1972. MOV SI,NAME_POINTER
  1973. CALL TTY_STRING ;display the filename
  1974. XOR AH,AH ;read the next key
  1975. INT 16H
  1976. MOV DI,NAME_END ;this points to the last letter
  1977. OR AL,AL ;is it a real character?
  1978. ; JZ NEXT_LETTER ;ignore special keys
  1979. JZ IS_ESCAPE ;special keys return to edit mode
  1980. CMP AL,1BH ;is it ESCape?
  1981. JE IS_ESCAPE ;continue with exit procedure
  1982. CMP AL,CR ;is it CR?
  1983. JE GOT_NAME
  1984. CMP AL,08H ;is it a backspace?
  1985. JE IS_BACKSPACE
  1986. CMP DI,81H + 65 ;too many letters?
  1987. JG NEXT_LETTER ;if yes, ignore them
  1988. XOR AH,AH ;for new terminal 0 to string
  1989. STOSW ;store the new letter and 0
  1990. INC NAME_END ;name is one character longer
  1991. JMP NEXT_LETTER ;read another keystroke
  1992. ;-----------------------
  1993. IS_ESCAPE:
  1994. POP ES ;get back file segment
  1995. POP DS
  1996. JMP REDO_PROMPT ;redraw the prompt and the screen
  1997. ;(CALL/RETurn) ;return to edit mode
  1998. ;-----------------------
  1999. GOT_NAME:
  2000. MOV DX,NAME_POINTER ;point to the filename
  2001. MOV AX,4300H ;get the file attribute
  2002. INT 21H ;DOS call
  2003. JNC NAME_OK ;if no error, filename is OK
  2004. CMP AX,3 ;was it "path not found" error?
  2005. JE BAD_NAME ;if yes, filename was bad
  2006. NAME_OK:
  2007. MOV SI,OFFSET DOT_$$$ ;point to the ".$$$"
  2008. MOV DI,OFFSET NAME_DOT_$$$
  2009. CALL CHG_EXTENSION ;add the new extension
  2010. MOV DX,OFFSET NAME_DOT_$$$ ;point to temp filename
  2011. MOV CX,0020H ;attribute for new file
  2012. MOV AH,3CH ;function to create file
  2013. INT 21H ;DOS call
  2014. JNC NAME_WAS_OK ;continue if name was OK
  2015. BAD_NAME:
  2016. MOV AX,0E07H ;write a bell character
  2017. INT 10H ;BIOS TTY service
  2018. JMP NEXT_LETTER ;get another letter
  2019. ;-----------------------
  2020. WRITE_ERROR:
  2021. MOV AH,3EH ;close the file
  2022. INT 21H ;DOS call
  2023. JMP BAD_NAME ;filename must be bad
  2024. ;-----------------------
  2025. NAME_WAS_OK:
  2026. XOR DX,DX ;this is the file buffer
  2027. MOV CX,LAST_CHAR ;number of chars in file
  2028. MOV BX,AX ;this is the handle
  2029. MOV AH,40H ;write to the file
  2030. POP DS ;recover the buffer segment
  2031. INT 21H ;write the buffer contents
  2032. POP DS
  2033. JC WRITE_ERROR ;exit on a write error
  2034. CMP AX,CX ;was entire file written?
  2035. JNE WRITE_ERROR ;if not, exit
  2036. PUSH CS
  2037. POP DS ;get the code segment
  2038. MOV AH,3EH ;close the temp file
  2039. INT 21H ;DOS call
  2040. MOV SI,OFFSET DOT_BAK ;point to the ".BAK"
  2041. MOV DI,OFFSET NAME_DOT_BAK
  2042. CALL CHG_EXTENSION ;make the backup filename
  2043. MOV DX,OFFSET NAME_DOT_BAK ;point to the backup name
  2044. MOV AH,41H ;delete existing backup file
  2045. INT 21H ;DOS call
  2046. MOV DI,OFFSET NAME_DOT_BAK
  2047. MOV DX,NAME_POINTER
  2048. MOV AH,56H
  2049. INT 21H ;DOS call
  2050. MOV DI,NAME_POINTER ;point to new filename
  2051. MOV DX,OFFSET NAME_DOT_$$$ ;point to temporary file
  2052. MOV AH,56H ;rename temp to new file
  2053. INT 21H ;DOS call, rename
  2054. POP AX ;restore the stack
  2055. POP AX
  2056. JMP SHORT FINISHED
  2057. ;(To return to DOS)
  2058. EXIT ENDP
  2059. ;-----------------------------------------------------------------------
  2060. ; This routine prompts for a verify keystroke then exits without saving 
  2061. ; the file.  If the file has not been altered, the edit file is abandoned 
  2062. ; and control is immediately returned to DOS.  
  2063. ;-----------------------------------------------------------------------
  2064. ABORT PROC NEAR
  2065. PUSH CS
  2066. POP DS
  2067. ASSUME DS:CSEG
  2068. TEST BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
  2069. JZ FINISHED ;file has not been altered.
  2070. MOV DH,ROWS ;last row on display
  2071. INC DH ;bottom row on screen
  2072. XOR DL,DL ;first column
  2073. MOV SI,OFFSET VERIFY_MESS
  2074. CALL TTY_STRING ;display verify message
  2075. XOR AH,AH ;read the next key
  2076. INT 16H ;BIOS read key routine
  2077. CMP AL,CR ;is it CR?
  2078. JE FINISHED
  2079. OR AL,20H ;convert to lower case
  2080. CMP AL,"y" ;was answer Yes?
  2081. JE FINISHED ;if yes, then we're finished
  2082. CALL REDO_PROMPT ;redraw the prompt and the screen
  2083. PUSH ES
  2084. POP DS ;set DS back to file segment
  2085. RET ;return to edit mode
  2086. ;-----------------------
  2087. FINISHED:
  2088. MOV DX,OFFSET COPYRIGHT
  2089. ;-----------------------
  2090. EXIT_TO_DOS: ;External entry point (DX, message)
  2091. PUSH CS
  2092. POP DS ;point to code segment
  2093. ASSUME DS:CSEG
  2094. CALL CLR_SCREEN ;clear the screen (passes DX through)
  2095. MOV AH,9 ;display error/exit message DS:DX
  2096. INT 21H ;DOS call
  2097. MOV AX,EXIT_CODE ;Exit to DOS with exit code
  2098. INT 21H ;DOS call
  2099. ABORT ENDP
  2100. ;=======================================================================
  2101. ; This routine copies the input filename to CS:DI and changes the extension.
  2102. ;-----------------------------------------------------------------------
  2103. CHG_EXTENSION PROC NEAR
  2104. ASSUME DS:CSEG, ES:CSEG
  2105. PUSH SI
  2106. MOV SI,NAME_POINTER
  2107. CHG_LOOP:
  2108. LODSB
  2109. CMP AL,"." ;look for the extension
  2110. JE FOUND_DOT
  2111. OR AL,AL
  2112. JZ FOUND_DOT
  2113. STOSB ;copy a character
  2114. JMP CHG_LOOP
  2115. ;-----------------------
  2116. FOUND_DOT:
  2117. MOV CX,5 ;five characters in extension
  2118. POP SI
  2119. REP MOVSB ;move new extension in
  2120. RET
  2121. CHG_EXTENSION ENDP
  2122. ;=======================================================================
  2123. ; This routine displays the string at CS:SI at the location in DX.  The 
  2124. ; remainder of the row is erased.  Cursor is put at the end of the line.
  2125. ;-----------------------------------------------------------------------
  2126. TTY_STRING PROC NEAR
  2127. ASSUME DS:CSEG
  2128. PUSH DX
  2129. CALL POSITION ;compute offset into video
  2130. POP DX
  2131. TTY_LOOP:
  2132. LODSB ;load DS:SI to AL
  2133. OR AL,AL ;at end of string yet?
  2134. JZ TTY_DONE
  2135. INC DL
  2136. PUSH DX
  2137. CALL WRITE_INVERSE ;write in inverse video
  2138. POP DX
  2139. JMP TTY_LOOP
  2140. ;-----------------------
  2141. TTY_DONE:
  2142. CALL SET_CURSOR ;move cursor to end of string
  2143. JMP ERASE_EOL ;erase the rest of the line
  2144. ;(CALL/RETurn)
  2145. TTY_STRING ENDP
  2146. ;=======================================================================
  2147. ; This routine clears the screen, leaves registers unaltered.
  2148. ;-----------------------------------------------------------------------
  2149. CLR_SCREEN PROC NEAR
  2150. ASSUME DS:NOTHING
  2151. PUSH AX ;save registers (for INT-24)
  2152. PUSH BX
  2153. PUSH CX
  2154. PUSH DX ;save DX for message address
  2155.   MOV DL,79 ;DL = right column
  2156. MOV DH,CS:ROWS ;DH = lower row
  2157. INC DH ;to clear the last line on the screen
  2158. MOV CX,0 ;CH = upper row, CL = left column
  2159. MOV BH,CS:NORMAL ;BH is blank line attribute, 07 = normal video
  2160. MOV AX,0600H ;scroll the cursor up (blank line)
  2161. INT 10H
  2162. XOR DX,DX ;set cursor to top left of screen
  2163. CALL SET_CURSOR
  2164. POP DX
  2165. POP CX
  2166. POP BX
  2167. POP AX
  2168. RET
  2169. CLR_SCREEN ENDP
  2170. ;=======================================================================
  2171. ; This is the control break handler for MS-DOS.  It ignores the break.
  2172. ; TED then responds by entering a <Ctrl-C> in the file.
  2173. ;-----------------------------------------------------------------------
  2174. NEWINT23 PROC FAR
  2175. ASSUME DS:NOTHING, ES:NOTHING
  2176. MOV CS:DIRTY_BITS,1 ;to redraw the screen
  2177. CLC ;tell DOS to ignore break
  2178. IRET
  2179. NEWINT23 ENDP
  2180. ;=======================================================================
  2181. ; This is the severe error handler.  It homes the cursor before 
  2182. ; processing the error.
  2183. ;-----------------------------------------------------------------------
  2184. NEWINT24 PROC FAR
  2185. ASSUME DS:NOTHING, ES:NOTHING
  2186. PUSHF
  2187. CALL CLR_SCREEN ;clear the screen and home the cursor
  2188. POPF
  2189. JMP CS:OLDINT24
  2190. ;(chain to old INT 24 handler)
  2191. NEWINT24 ENDP
  2192. ;=======================================================================
  2193. ; This is the location of the character string search buffer.  It occupies 
  2194. ; the last three bytes in the program file.  The following 64-bytes are used 
  2195. ; for the buffer area.  The third byte is also used as the program code 
  2196. ; check-sum compensation byte.
  2197. ;-----------------------------------------------------------------------
  2198. EVEN
  2199. SRCH_MAX DB 66 ;42H, maximum size of buffer
  2200. SRCH_SIZ DB 0 ;number of char's actually in buffer
  2201. SRCH_STR DB 0 ;start of buffer block
  2202. ;This is the correction byte for the check-sum test
  2203. CHEK_SUM_BYT    DB      0103
  2204. ;=======================================================================
  2205. NAME_DOT_$$$ EQU $ +64 ;128 bytes
  2206. NAME_DOT_BAK EQU $+80H +64 ;128 bytes
  2207. UNDO_BUFFER EQU $+100H +64 ;256 bytes, Del key buffer
  2208. LINE_BUFFER EQU $+200H +64 ;256 bytes, Delete line, EOL
  2209. END_BUFFER EQU $+300H +64 +15 ;end of buffers, file segment follows
  2210. ; +15 is for paragraph rounding
  2211. CSEG ENDS
  2212. ;-----------------------------------------------------------------------
  2213. FILE_SEG SEGMENT
  2214. FILE_SEG ENDS
  2215. END START