📄 cmdedit.asm
字号:
@get_next_line_99:
ret
get_next_line endp
;+
; FUNCTION : replace_vars
;
; Replaces all the variables in the current line with their
; expansions. If the line is too long, aborts with a truncation
; error.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
; AX,BX,CX,DX
;-
replace_vars proc near
call near ptr expand_var ;CF set if error. AX
; contains error code
jnc @replace_vars_99
jmp near ptr abort_processing ;Abort processing
@replace_vars_99:
ret
replace_vars endp
;+
; FUNCTION : get_curpos
;
; Returns the current cursor position.
;
; Parameters:
; Global video_page indicates the page.
;
; Returns:
; DX = Current cursor position.
; CX = Current cursor scan lines.
; Register(s) destroyed: AX,BX
;-
get_curpos proc near
@GetCur video_page
ret
get_curpos endp
;+
; FUNCTION : set_disp_marks
;
; Sets the marks disp_begin and disp_end to indicate the start
; and end positions in the line that have been changed. The
; routine is passed two parameters which indicate
; the potentially new values for disp_begin and disp_end
; respectively. However the global disp_begin is changed only if
; the new value is less than the current value. Similarly
; disp_end is changed only if the new value is greater than the
; current value.
;
; Parameters:
; AX = potential disp_end
; DX = potential disp_begin
;
; Returns:
; Nothing.
; May set globals disp_begin and disp_end.
;
; Register(s) destroyed: None.
;-
set_disp_marks proc near
cmp ax,disp_end ;New value greater ?
jb @set_disp_marks_10 ;No
mov disp_end,ax ;New disp_end
@set_disp_marks_10:
cmp dx,disp_begin ;New value smaller
jnb @set_disp_marks_20 ;No
mov disp_begin,dx ;New disp_begin
@set_disp_marks_20:
ret
set_disp_marks endp
;+
; FUNCTION : disp_line
;
; Displays the current contents of the line buffer. Since the
; entire line is not redisplayed everytime, all procedures that
; change the contents of the line buffer have to follow certain
; rules in order to make sure the display correctly shows the
; line. The variable disp_begin must be set to the earliest
; position in the line that has been changed and disp_end to beyond
; last position in the line that has been changed.;
; Parameters:
; None.
;
; Returns:
; Nothing
; Register(s) destroyed:
;-
disp_line proc near
@save si,di
mov ax,disp_begin ;Lower limit of changed chars
mov si,ax
mov cx,disp_end ;CX->byte after last char that
; has changed
sub cx,si ;CX<-num chars to be output
jcxz @disp_line_90 ;Nothing to be updated
push cx ;Save CX across calls
call near ptr line_to_scr ;Move cursor to corresponding
; position on the screen.
; OK, now we are ready to begin updating the screen.
call near ptr get_curpos ;DX<-current cursor position
pop cx ;Restore CX
mov di,lastchar ;DI->beyond last char
cmp si,di ;Beyond last char?
je @disp_line_25 ;Go display blanks
@disp_line_10: ;Loop to output chars
lodsb ;AL<-next char
@DispCh al ;Display it
push cx ;Save CX
push dx ;Save old cursor position
call near ptr get_curpos ;DX<-new cursor position
; BX destroyed
pop bx ;BX<-old cursor position
pop cx ;Restore CX
or dl,dl ;Column 0 ?
jne @disp_line_20 ;Nope
;Col 0
cmp bh,dh ;Is the row the same
jne @disp_line_20
;yes, screen scrolled
dec initial_curpos+1 ;Decrement the row for initial
; cursor position
@disp_line_20:
mov bx,dx ;New cursor position
cmp si,di ;Beyond last char?
loopne @disp_line_10 ;Keep looping until count exhausted or
; beyond last char
@disp_line_25:
; Now all changed positions have been displayed. If CX is not 0,
; then the remaining char positions have to be
; replaced with blanks. Note that since we are now overwriting
; previously displayed positions, no need to check for line
; wraparound or scroll.
jcxz @disp_line_90 ;No more chars
mov al,' ' ;Overwrite with blanks
@disp_line_30:
@DispCh al
loop @disp_line_30
@disp_line_90:
mov ax,dot
mov disp_begin,ax ;Initialize for next call
mov disp_end,ax
call near ptr line_to_scr ;Set cursor at dot
@restore
ret
disp_line endp
;+
; FUNCTION : line_to_scr
;
; Places the cursor at the screen position corresponding to a
; specific position in the line buffer. The entire line buffer
; upto that position must have been displayed before.
;
; Parameters:
; AX = Pointer into the line buffer
;
; Returns:
; Nothing.
; Register(s) destroyed: AX, BX, DX
;-
line_to_scr proc near
sub ax,offset dgroup:linebuf ;ax<-num chars
mov dx,initial_curpos ;Initial cursor position
; dh<-row, dl<-column
xor bh,bh
mov bl,dl ;BX<-original column
add ax,bx ;Compensate for initial position.
; AX is now the 'virtual column'
mov bl,screen_width ;BX<-width of screen
@line_to_scr_10: ;Loop to skip over chars that
; do not need to be updated
cmp ax,bx ;Num of chars fit on a line?
jb @line_to_scr_20 ;Yes, exit loop
sub ax,bx ;Go to next line
inc dh ;Increment the row
jmp short @line_to_scr_10
@line_to_scr_20:
; al now contains the column and dh the row where the cursor should
; be placed
mov dl,al ;dx<-screen position
@SetCurPos ,,video_page ;Set the cursor position
ret
line_to_scr endp
;+
; FUNCTION : insert_chars
;
; Inserts a string of chars at the specified position in the
; linebuffer. If the length would exceed the size of the line buffer,
; chars are only store until the buffer is full and the carry flag is
; set. Dot is updated appropriately.
;
; Parameters :
;
; SI - ptr to source string
; DI - ptr to insert position. This must lie in the line buffer.
; AX - length of source string
;
; Returns:
; CF = 1 if could not be fitted into linebuf
; 0 otherwise
;
; Registers destroyed:
; AX,CX,DX
insert_chars proc near
@save si,di
mov dx,di ;Save insert position in DX
mov di,lastchar ;First empty position
mov cx,offset DGROUP:linebuf_suffix
sub cx,di ;Subtract current last position
; CX<-max chars that will fit
cmp cx,ax ;Will all chars fit ?
jb @insert_chars_5 ;Not all chars will fit
xchg ax,cx ;All chars will fit
@insert_chars_5:
; CX is number of chars to insert
pushf ;Remember CF
; Make place for the characters to be inserted by moving current
; characters up by CX.
mov ax,di
sub ax,dx ;AX<-num chars to move
push si ;Remember source address
mov si,di ;SI->first char to be moved
add di,cx ;DI -> new value of lastchar
mov lastchar,di ;Store it
xchg ax,cx ;AX<-num chars to insert
; CX<-num chars to move
std ;Direction is downward
cmpsb ;Decrement SI,DI
rep movsb ;Make place
cld
pop si ;Restore string source
; Before inserting the chars, update the dot if it is affected.
cmp dx,dot ;Is the dot at or after the insert
; position ?
jb @insert_chars_50 ;No, jump
add dot,ax ;Else update the dot
@insert_chars_50:
mov di,dx ;DI->insert position
xchg cx,ax ;CX<-num chars to insert
rep movsb ;Copy string into linebuffer
mov ax,lastchar
call near ptr set_disp_marks ;AX,DX are parameters
popf ;Restore CF
@restore
ret
insert_chars endp
;+
; FUNCTION : insert_at_dot
;
; Inserts a string of characters into the line buffer in the
; position pointed to by dot. If the length specified in global
; caller_buflen will be exceeded,chars are only stored until the
; buffer is full and CF is set.
;
; Parameters:
; SI = ptr to source string
; AL = length of string
;
; Returns:
; CF = 1 if could not be fitted into linebuf
; 0 otherwise
; Register(s) destroyed:
; <TBA>
;-
insert_at_dot proc near
@save si,di,dx
xor ah,ah ;AX<-length of source string
mov di,dot ;DI-> insert position
call near ptr insert_chars ;Params SI,DI,AX, returns status in CF
@restore
ret
insert_at_dot endp
;+
; FUNCTION : remove_chars
;
; Removes a string of chars at the specified position in the
; linebuffer. The display markers and the lastchar global are updated
; accordingly.
;
; Parameters :
;
; SI - ptr to position in linebuf from which to delete
; AX - number of chars to delete.
;
; Returns:
; Nothing.
;
; Registers destroyed:
; AX,CX,DX
remove_chars proc near
@save si,di
mov di,ax ;Save delete count
; First update the display markers
mov ax,lastchar
mov dx,si
call near ptr set_disp_marks ;AX,DX params
mov ax,lastchar
sub ax,si ;Num chars after delete position
cmp ax,di ;More than the specified number ?
jb @remove_chars_10 ;No, so just delete that many bytes
mov ax,di
@remove_chars_10:
; AX is number of bytes to delete. See if the dot needs to be updated.
mov di,si ;DI->delete position
add si,ax ;SI->first char after delete string
cmp di,dot
jnb @remove_chars_40 ;dot before delete pos, so
; unaffected
cmp si,dot ;Is dot beyond it delete range
jb @remove_chars_30 ;Yes
; dot is in delete region. Update it to point to first delete position
mov dot,di
jmp short @remove_chars_40
@remove_chars_30:
; dot is beyond delete position. So subtract delete bytes from it.
sub dot,ax
@remove_chars_40:
; Now that the screen markers and dot have been updated, get down to the
; real business at hand. SI points to first char after delete string, DI is
; the delete position. AX is number of bytes to be deleted.
mov cx,lastchar
sub lastchar,ax ;Update lastchar
sub cx,si ;CX<-num bytes to move
rep movsb ;Move 'em
; All done
@restore
ret
remove_chars endp
;+
; FUNCTION : erase_to_dot
;
; Deletes all characters from the line buffer between the
; positions AX and dot. (Either AX or dot may be specify the
; beginning of range to be deleted). The markers disp_begin and
; disp_end are set to reflect the changed positions in the line.
; Global lastchar is also updated.
; Parameters:
; AX = One endpoint of the range to be deleted.
; Global dot is the other.
; Returns:
; Nothing.
; Register(s) destroyed:
;-
erase_to_dot proc near
@save si
mov si,dot
cmp ax,si ;Make sure AX is after dot
jnb @erase_to_dot_10 ;Yes it is
xchg si,ax ;Else exchange
@erase_to_dot_10: ;AX is low end, SI high end
sub ax,si ;AX is num bytes to delete
call near ptr remove_chars ;Delete AX chars starting at [SI]
@restore
ret
erase_to_dot endp
;+
; FUNCTION : cmdedit_cmd
;
; Checks if the line buffer contains a CMDEDIT command and if so
; executes it.
;
; Parameters:
; None.
;
; Returns:
; CF = 0 if the line was a command
; 1 otherwise.
; Register(s) destroyed:
; AX,BX,CX,DX
;-
cmdedit_cmd proc near
@save si,di
mov si,offset DGROUP:linebuf ;SI->linebuf
mov di,lastchar ;DI->end of line in linebuf
; Skip leading whitespace
mov cx,di
sub cx,si ;CX<-num chars in linebuf
call near ptr skip_whitespace ;SI->first non-whitespace char
; CX<-num remaining chars
jcxz @cmdedit_cmd_99 ;No command on line
mov di,si ;DI->first char of word
; Skip first word (name of this command)
call near ptr skip_nonwhite ;SI->first whitespace after
; command name
; CX<-num remaining chars
mov ax,si
sub ax,di ;AX<-num chars in word
cmp ax,MAX_CMD_LEN ;Word too long to be command?
ja @cmdedit_cmd_98 ;Yes, exit
; Now search thru the command table to see if the first word in the line is a
; CMDEDIT command. Currently, DI->start of word, AX = num chars in word
xor dx,dx ;DX<-Command number
mov si,offset dgroup:cmd_table ;SI->Start of commands
@cmdedit_cmd_10:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -