📄 ted2.asm
字号:
ASSUME DS:CSEG
MOV STATUS_REG,AX
CMP AX,3BAH ;is this a MONO display?
JNE COLOR ;if not, must be a CGA
MOV WORD PTR HWAIT,NO_DESNOW ;get rid of desnow
JMP SHORT MOVE_STACK
COLOR:
MOV VIDEO_SEG,0B800H ;segment for color card
XOR BH,BH ;use page zero
MOV AH,8 ;get current attribute
INT 10H
AND AH,77H ;turn off blink and high intensity
MOV NORMAL,AH ;save the normal attribute
XOR AH,01110111B ;flip the color bits
MOV INVERSE,AH
OR AH,80H
MOV SRCH_CLR,AH ;search is inverse/blink
MOVE_STACK:
MOV BX,OFFSET END_BUFFER
;**rounding ADD BX,15 ;add offset value for SEG rounding up
MOV CL,4 ;convert program size to
SHR BX,CL ; paragraphs
MOV AH,4AH ;deallocate unused memory
INT 21H ;DOS call
MOV BX,1000H ;request 64K for file segment
MOV AH,48H
INT 21H ;DOS call
MOV ES,AX
ASSUME ES:FILE_SEG
MOV AH,48H ;request 64K for paste buffer
INT 21H ;DOS call
JNC GOT_ENOUGH ;if enough memory, continue
NOT_ENOUGH:
MOV DX,OFFSET MEMORY_ERROR
EXIT_2_DOS: JMP EXIT_TO_DOS ;jump island to allow SHORT jumps.
;-----------------------
GOT_ENOUGH:
MOV PASTE_SEG,AX ;use this for the paste buffer
GET_FILENAME:
MOV SI,80H ;point to command tail in PSP
MOV CL,[SI] ;get number of characters in tail
XOR CH,CH ;make it a word
INC SI ;point to first character
PUSH SI
ADD SI,CX ;point to last character
MOV BYTE PTR [SI],0 ;make it an ASCIIZ string (clear the CR)
MOV NAME_END,SI ;save pointer to last character
POP SI ;get back pointer to filename
JCXZ NO_FILENAME ;if no params, just exit
CLD
DEL_SPACES:
LODSB ;get character into AL
CMP AL," " ;is it a space?
JNE FOUND_LETTER
LOOP DEL_SPACES
FOUND_LETTER:
DEC SI ;backup pointer to first letter
MOV NAME_POINTER,SI ;save pointer to filename
MOV DX,NAME_POINTER
MOV AX,4300H ;get file attribute byte (in CL)
INT 21H ;DOS call
JC ATTRIB_ERROR
AND CL,1 ;keep bit-0, read-only status
ADD CL,CL ;shift RO bit up
OR INSERT_MODE,CL ;save as index modifier value
ATTRIB_ERROR:
MOV DX,SI
MOV AX,3D00H ;setup to open file
INT 21H ;DOS call
; If no carry, Then the opened file handle is in AX
; If no carry, Then the opened file handle is in AX
JC NO_FILENAME ;if we can't open, must be new file
FILE_OPENED:
PUSH ES
POP DS ;DS has file segment also
ASSUME DS:FILE_SEG
MOV BX,AX ;get the handle into BX
XOR DX,DX ;point to file buffer, DS:DX
MOV CX,0FFFEH ;read almost 64K bytes
MOV AH,3FH ;read from file or device
; BX = file handle
INT 21H ;DOS call
; If no carry, Then AX contains number of bytes read
MOV DI,AX ;number of bytes read in
JNC FILE_READ_OK ;if no error, take jump
MOV DX,OFFSET READ_ERR_MESS
;-----------------------
; the file has been opened, it should now be closed. (JEG)
;-----------------------
CLOSE_ERR_EXIT:
MOV AH,3EH ;close the opened file
; BX = file handle
INT 21H
JMP SHORT EXIT_2_DOS
;-----------------------
FILE_READ_OK:
MOV LAST_CHAR,DI ;save the file size
CMP CX,AX ;did the buffer fill?
MOV DX,OFFSET FILE_TOO_BIG
JE CLOSE_ERR_EXIT ;if yes, it is too big
MOV AH,3EH ;close the file
; BX = file handle
INT 21H
;**dirty MOV BYTE PTR CS:DIRTY_FILE,0 ;file opened but not altered.
NO_FILENAME:
PUSH ES
PUSH ES ;save the file segment
PUSH CS
POP DS
ASSUME DS:CSEG
;-----------------------
;INT 24 is the critical error handler
;-----------------------
MOV AX,3524H ;get INT 24 vector
INT 21H ;DOS call
MOV WORD PTR OLDINT24,BX ;store the offset
MOV WORD PTR OLDINT24+2,ES ;and the segment
MOV DX,OFFSET NEWINT24 ;point to new vector
MOV AX,2524H ;now change INT 24 vector
INT 21H ;DOS call
;-----------------------
;INT 23 is the CTRL-Break or CTRL-C handler
;-----------------------
MOV DX,OFFSET NEWINT23
MOV AX,2523H ;set the INT 23 vector
INT 21H ;DOS call
POP ES ;get back file segment
POP DS
ASSUME DS:FILE_SEG
CALL REDO_PROMPT ;draw the prompt line
;-----------------------------------------------------------------------
; Here's the main loop. It updates the screen, then reads a keystroke.
;-----------------------------------------------------------------------
READ_A_KEY:
CMP MARK_MODE,0 ;is the mark state on?
JZ MARK_OFF ;if not, skip this
OR DIRTY_BITS,4 ;refresh the current row
MOV DX,CURS_POSN
CMP SAVE_ROW,DH ;are we on the save row?
JE SAME_ROW ;if yes, then redo the row only
OR DIRTY_BITS,1 ;refresh the whole screen
SAME_ROW:
MOV AX,CURSOR ;get cursor location
MOV BX,MARK_HOME ;get the anchor mark position
CMP AX,BX ;moving backward in file?
JAE SAME1
MOV MARK_START,AX ;switch start and end positions
MOV MARK_END,BX
JMP SHORT MARK_OFF
SAME1:
MOV MARK_END,AX ;store start and end marks
MOV MARK_START,BX
MARK_OFF:
CALL DISPLAY_SCREEN ;redraw the screen
XOR AH,AH ;read the next key (wait if none ready)
INT 16H ;BIOS call
; AL = ASCII code or 0 (for function keys)
; AH = scan code
TEST SRCH_FLG,0FFH
JZ CHECK_KEY ;jump if inverse not on
MOV SRCH_FLG,0 ;turn off highlight
OR DIRTY_BITS,1 ;redraw screen (next time)
CHECK_KEY:
OR AL,AL ;is this an extended code?
JZ IS_EXTENDED_CODE ;(jump if not an ASCII character)
CALL INSERT_KEY ;put this ASCII character in the file
;**short JMP READ_A_KEY ;get another key
JMP SHORT RD_NEXT_KEY ;get another key
;---------------------------------------
IS_EXTENDED_CODE:
;-----------------------
; The following code is for "orphan" key codes and alias keys
;-----------------------
CMP AH,132 ;is it Ctrl-PgUp? (an orphan code)
JNE NOT_CT_PGUP
CALL CTRL_PGUP
;**short JMP READ_A_KEY
JMP SHORT RD_NEXT_KEY ;get another key
;-----------------------
NOT_CT_PGUP:
CMP AH,32 ;is it Alt-D (MultiEdit Del-EOL)?
JNE NOT_ALT_D
MOV AH,66 ;substitute scan code for F8
NOT_ALT_D:
CMP AH,31 ;is it Alt-S (BSE string search)?
JNE NOT_ALT_S
MOV AH,64 ;substitute scan code for F6
NOT_ALT_S:
CMP AH,30 ;is it Alt-A (BSE search again)?
JNE NOT_ALT_A
MOV AH,89 ;substitute scan code for Shft-F6
NOT_ALT_A:
;-----------------------
; The following code sets up a PASCAL style CASE statement.
;-----------------------
CMP AH,DISPATCH_END ;split the dispatch table
JB DO_DISPATCH
;-----------------------
; offset cursor group of keys to join the regular dispatch table.
;-----------------------
CMP AH,DISP_CURS_BASE
JB RD_NEXT_KEY
CMP AH,DISP_CURS_END
JAE RD_NEXT_KEY
SUB AH,LOW (DISP_CURS_BASE - DISPATCH_END) ;close table gap
DO_DISPATCH:
;-----------------------
; This is a PASCAL style CASE statement.
;-----------------------
MOV BX,AX ;put AH offset value in BX, AL=0
XCHG BL,BH ;make into a proper word
SUB BX,DISPATCH_BASE ;zero offset for dispatch table jump
JC RD_NEXT_KEY ;too low, not in table
ADD BX,BX ;make into word
CALL CS:DISPATCH_TABLE[BX] ;call the key procedure
RD_NEXT_KEY: JMP READ_A_KEY ;then read another key
;=======================================================================
; KEYBOARD and CURSOR services
;=======================================================================
; These two routines shift the display right or left to allow editing
; files which contain lines longer than 80 columns. Starting with TED2,
; they are proper subroutines.
;-----------------------------------------------------------------------
SH_LEFT PROC NEAR
CMP LEFT_MARGIN,0 ;at start of line already?
JE NO_SHIFT ;if yes,then don't shift
SUB LEFT_MARGIN,8 ;move the window over
JMP SHORT SH_RETURN
SH_LEFT ENDP
;-----------------------------------------------------------------------
SH_RIGHT PROC NEAR
CMP LEFT_MARGIN,255 - 8 ;past max allowable margin?
JAE NO_SHIFT ;then can't move any more
ADD LEFT_MARGIN,8 ;this moves the margin over
SH_RETURN:
CALL CURSOR_COL ;compute column for cursor
MOV SAVE_COLUMN,DL ;save the current column
OR DIRTY_BITS,1 ;redraw the screen
NO_SHIFT:
;**dispatch JMP READ_A_KEY
;**bad_key RET
SH_RIGHT ENDP
;-----------------------------------------------------------------------
; DISPATCH_TABLE calls to BAD_KEY now go here so that the stack can be
; kept equallized.
;-----------------------------------------------------------------------
BAD_KEY PROC NEAR
RET
BAD_KEY ENDP
;=======================================================================
; This routine moves the cursor to the top of the file.
;-----------------------------------------------------------------------
TOP PROC NEAR
XOR AX,AX ;get a zero into AX
MOV CURSOR,AX ;cursor to start of file
MOV TOP_OF_SCREEN,AX
MOV LEFT_MARGIN,AL ;move to far left margin
MOV CURS_POSN,AX ;home the cursor
MOV SAVE_COLUMN,AL ;save the cursor column
MOV DIRTY_BITS,3 ;redraw the screen and cursor
RET
TOP ENDP
;=======================================================================
; This routine moves the cursor to the bottom of the file.
;-----------------------------------------------------------------------
BOTTOM PROC NEAR
MOV DH,ROWS ;get screen size
MOV SI,LAST_CHAR ;point to last character
;-----------------------
; from TEDPLUS
DEC SI
;-----------------------
MOV LEFT_MARGIN,0 ;set window to start of line
CALL LOCATE ;adjust the cursor screen position
CALL HOME ;move cursor to start of line
MOV DIRTY_BITS,1 ;this will redraw the screen
RET
BOTTOM ENDP
;=======================================================================
; This routine moves the cursor to the start of the current line.
; If <HOME> key and already at start of line, move to start of previous line.
;-----------------------------------------------------------------------
HOME_KEY PROC NEAR
CALL LEFT ;back up one space, in case at home
HOME_KEY ENDP
HOME PROC NEAR
CALL FIND_START ;find start of line
MOV CURSOR,SI ;save the new cursor
MOV SAVE_COLUMN,0 ;save the cursor column
MOV BYTE PTR CURS_POSN,0 ;store the column number
RET
HOME ENDP
;=======================================================================
; These routines move the cursor right and left
;-----------------------------------------------------------------------
RIGHT PROC NEAR
MOV SI,CURSOR
CMP SI,LAST_CHAR ;at end of file?
JE LR_NO_CHANGE ;if yes, then can't move
;-----------------------
; from TEDPLUS
INC SI
CMP SI,LAST_CHAR ;at end of file?
DEC SI
JAE INC_RIGHT ;if yes, then increment
CMP WORD PTR [SI],CRLF ;is it CRLF?
JE MOVE_DOWN ;if yes, then move down to next line
INC_RIGHT:
;-----------------------
INC CURSOR ;advance the cursor
JMP SHORT LR_RETURN
MOVE_DOWN:
CALL HOME ;move to start of line
JMP SHORT DOWN ;and move down one row
;(CALL/RETurn)
RIGHT ENDP
;-----------------------------------------------------------------------
LEFT PROC NEAR
CMP CURSOR,0 ;at start of file?
JZ LR_NO_CHANGE ;then can't move left
MOV DX,CURS_POSN
OR DL,DL ;at first column?
JZ MOVE_UP ;if yes, then move up one
DEC CURSOR ;shift the cursor offset
LR_RETURN:
CALL CURSOR_COL ;compute column for cursor
MOV SAVE_COLUMN,DL ;save the cursor column
LR_NO_CHANGE:
MOV UNDO_LENGTH,0
RET
;-----------------------
MOVE_UP:
CALL UP ;move up to next row
JMP SHORT ENDD ;and move to end of line
;(CALL/RETurn)
LEFT ENDP
;-----------------------------------------------------------------------
; This routine moves the cursor to the end of the current line.
; If END key and already at end of line, move to end of next line.
;-----------------------------------------------------------------------
END_KEY PROC NEAR
CALL RIGHT ;move one space right, if at EOL
END_KEY ENDP
ENDD PROC NEAR
MOV SI,CURSOR
CALL FIND_EOL ;find end of this line
MOV CURSOR,SI ;store the new cursor
CALL CURSOR_COL ;compute the correct column
MOV SAVE_COLUMN,DL ;save the cursor column
RET
ENDD ENDP
;-----------------------------------------------------------------------
; This routine moves the cursor down one row. When the last row is reached,
; the screen is shifted up one row.
;-----------------------------------------------------------------------
DOWN PROC NEAR
MOV UNDO_LENGTH,0
MOV DX,CURS_POSN
CMP DH,ROWS ;at bottom row already?
MOV SI,CURSOR ;get position in file
JE SCREEN_UP ;if at bottom, then scroll up
CALL FIND_NEXT ;find the start of next line
JC DOWN_RET ;if no more lines, then return
MOV CURSOR,SI
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -