mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
1112 lines
31 KiB
Plaintext
1112 lines
31 KiB
Plaintext
; File : $CMDLINE.A86$
|
|
;
|
|
; Description :
|
|
;
|
|
; Original Author : DIGITAL RESEARCH
|
|
;
|
|
; Last Edited By : $CALDERA$
|
|
;
|
|
;-----------------------------------------------------------------------;
|
|
; Copyright Work of Caldera, Inc. All Rights Reserved.
|
|
;
|
|
; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
|
|
; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
|
|
; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
|
|
; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
|
|
; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
|
|
; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
|
|
; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
|
|
; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
|
|
; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
|
|
; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
|
|
; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
|
|
; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
|
|
; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
|
|
; CIVIL LIABILITY.
|
|
;-----------------------------------------------------------------------;
|
|
;
|
|
; *** Current Edit History ***
|
|
; *** End of Current Edit History ***
|
|
;
|
|
; $Log$
|
|
; CMDLINE.A86 1.8 93/03/25 15:06:03
|
|
; tweak console block output
|
|
; ENDLOG
|
|
;
|
|
; DOSPLUS Command Line Editor Routines
|
|
;
|
|
|
|
include pcmode.equ
|
|
include i:msdos.equ
|
|
include i:char.def
|
|
include i:cmdline.equ
|
|
include i:reqhdr.equ
|
|
include i:driver.equ
|
|
|
|
|
|
PCM_CODE CSEG BYTE
|
|
public read_line, edit_size
|
|
|
|
extrn dbcs_lead:near
|
|
extrn cmdline_read:near
|
|
extrn raw_read:near
|
|
extrn cooked_write:near
|
|
extrn get_dseg:near
|
|
extrn device_driver:near
|
|
|
|
; WARNING - the following routines are to support history buffers
|
|
; As these are optional we muset NEVER call these routines unless
|
|
; the HISTORY_ON bit is set in @hist_flag.
|
|
|
|
extrn init_history:near
|
|
extrn save_history:near
|
|
extrn prev_cmd:near
|
|
extrn next_cmd:near
|
|
extrn match_cmd:near
|
|
extrn search_cmd:near
|
|
extrn match_word:near
|
|
extrn del_cur_history_buffer:near
|
|
extrn del_history_buffers:near
|
|
extrn goto_eol:near
|
|
extrn next_word:near
|
|
extrn prev_word:near
|
|
extrn del_bol:near
|
|
extrn deln_word:near
|
|
|
|
; The following are public for HISTORY.PCM
|
|
public next_char, save_line
|
|
public space_out, bs_out, put_string
|
|
public goto_bol
|
|
public del_eol, del_line
|
|
public char_info
|
|
public prev_w20
|
|
public deln_w10
|
|
|
|
|
|
; READ_LINE will read an editted line from the handle passed in BX
|
|
; into a buffer with the following format:-
|
|
;
|
|
; BYTE Maximum String Length
|
|
; BYTE Current String Length
|
|
; BYTE(s) String Buffer
|
|
;
|
|
; On Entry:-
|
|
; BX Input Handle
|
|
; CX Output Handle
|
|
; ES:DX Buffer Address
|
|
;
|
|
; On Exit:-
|
|
; String input by user
|
|
;
|
|
; The following conventions apply for the READ_LINE function
|
|
;
|
|
; ES Buffer segment
|
|
; SI Current cursor location in buffer (Index)
|
|
; DX Last Character in Buffer (Index)
|
|
;
|
|
DISABLE equ 80h ; Disable when advanced editing is off.
|
|
DISABLE_MASK equ 8000h
|
|
ESC_CODE equ 01h ; Scan code must be preceeded by escape byte.
|
|
NESC_CODE equ 00h ; No lead zero needed.
|
|
|
|
read_line:
|
|
push bp ; Save the Stack Frame Pointer
|
|
mov bp,sp ; Intialise it to the top of the
|
|
sub sp,RL_LENGTH ; READ_LINE control block and reserve
|
|
; control block
|
|
mov RL_INPUT,bx ; Initialize the INPUT Handle
|
|
mov RL_OUTPUT,cx ; the OUTPUT Handle
|
|
inc dx ! inc dx ; Skip max and Returned Length
|
|
mov RL_BUFOFF,dx ; and save the buffer offset
|
|
mov RL_BUFSEG,es ; and segment
|
|
xor ax,ax ; now we zero
|
|
mov RL_SAVPOS,ax ; both position in it
|
|
mov RL_SAVMAX,ax ; and it's size
|
|
mov al,column
|
|
mov RL_INICOL,ax ; save initial column
|
|
mov ax,cle_state ; use to set initial editing state
|
|
and ax,not (RLF_MATCH+RLF_DIRTY+RLF_RECALLED)
|
|
mov RL_FLAGS,ax ; save in flags
|
|
test ax,RLF_ENHANCED
|
|
jz read_line10
|
|
call init_history ; setup the history buffers
|
|
jmps read_line20
|
|
read_line10:
|
|
and RL_FLAGS,not RLF_INS ; clear insert mode
|
|
read_line20:
|
|
mov di,dx ; di -> buffer
|
|
xor bx,bx
|
|
or bl,es:byte ptr -2[di] ; Get the Maximum number of chars
|
|
mov RL_MAXLEN,bx ; and save for later
|
|
jnz read_line30 ; make sure some chars are requested
|
|
jmps ret_string10 ; if no chars just return
|
|
|
|
ret_string:
|
|
pop ax ; Remove local return address
|
|
mov ax,RL_FLAGS ; get command line editor state
|
|
mov cle_state,ax ; save state for next time
|
|
mov di,RL_BUFOFF ; Get the buffer Offset
|
|
mov es:byte ptr -1[di],dl ; Return the number of characters
|
|
push dx ; Save length of entry
|
|
add di,dx ; Point to the end of the buffer
|
|
mov al,CR
|
|
stosb ; Save CR
|
|
call write_char ; Print a CR and return to the user
|
|
pop dx
|
|
test RL_FLAGS,RLF_ENHANCED ; Do not add to history if in
|
|
jz ret_string10 ; compatibility mode
|
|
call save_history ; Save state of history buffer
|
|
ret_string10:
|
|
mov sp,bp ; Remove READ_LINE control Block
|
|
pop bp ; Restore BP and return to the caller
|
|
ret
|
|
|
|
|
|
read_line30:
|
|
xor si,si ; Currently at start of buffer
|
|
mov dx,si ; with an empty buffer.
|
|
|
|
xor bx,bx
|
|
or bl,es:byte ptr -1[di] ; Check if the buffer contains any
|
|
jz read_line40 ; data which is terminated by a CR
|
|
cmp es:byte ptr [bx+di],CR
|
|
jnz read_line40
|
|
mov dx,bx
|
|
read_line40:
|
|
call save_line ; Update Save Buffer variables
|
|
mov dx,si
|
|
;
|
|
; This is out main command loop - we get a character and try to match it
|
|
; with a command in our edit_table. If History is on we look at commands
|
|
; with the DISABLED bit set ie. enhanced commands.
|
|
; It a match isn't found we insert the character in the buffer, and optionally
|
|
; try to match with previous lines in the history buffer.
|
|
;
|
|
read_line_loop:
|
|
and RL_FLAGS,not RLF_KANJI ; initial flags
|
|
call get_char ; read the first character (AH Esc Flg)
|
|
|
|
mov cx,edit_size ; now scan the control table looking
|
|
mov bx,offset edit_table ; for a match
|
|
read_ll_next_cmd:
|
|
and ax,not DISABLE_MASK ; assume normal function
|
|
test RL_FLAGS,RLF_ENHANCED ; compatibilty required? then it
|
|
jz read_ll10 ; has to be a normal function
|
|
test EDIT_CNTRL,DISABLE_MASK ; history enabled, so we make
|
|
jz read_ll10 ; our code match DISABLE mask
|
|
or ax,DISABLE_MASK ; of table entry
|
|
read_ll10:
|
|
cmp ax,EDIT_CNTRL ; check for a match (Escape Flag
|
|
je read_ll_found_cmd ; and the character)
|
|
add bx,EDIT_LEN ; Add the entry length
|
|
loop read_ll_next_cmd ; and scan the whole table
|
|
|
|
; We have failed to find a command so insert char in buffer
|
|
|
|
test ah,ESC_CODE ; Ignore non-matched escaped keys
|
|
jnz read_line_loop
|
|
|
|
call save_char ; not an command so save the character
|
|
or RL_FLAGS,RLF_DIRTY ; and remember we have something new
|
|
|
|
; Are we in search mode ?
|
|
|
|
test RL_FLAGS,RLF_ENHANCED ; Compatibilty required?
|
|
jz read_line_loop
|
|
test RL_FLAGS,RLF_SEARCH+RLF_MATCH
|
|
jz read_line_loop ; is searching/matching on ?
|
|
push si ; save current offset
|
|
call search_cmd
|
|
pop ax ; this is our target offset
|
|
read_ll20:
|
|
cmp ax,si ; are we there yet ?
|
|
jae read_line_loop
|
|
push ax ; no, keep rewinding cursor
|
|
call prev_char ; until we reach position
|
|
pop ax ; before we tried to match
|
|
jmps read_ll20
|
|
|
|
read_ll_found_cmd: ; get the address of the corresponding
|
|
mov cx,EDIT_FUNC ; function from the table
|
|
call cx ; execute the correct function
|
|
jmps read_line_loop ; and go back for next character
|
|
|
|
eject
|
|
;
|
|
; the SAVE_CHAR routine will write the character in AL into
|
|
; the buffer in memory and then update the screen image. The
|
|
; RLF_INS flag is used to determine if INSERT is active.
|
|
;
|
|
save_c10:
|
|
ret
|
|
|
|
save_char:
|
|
cmp ah,TRUE ; Ignore any un-matched escape
|
|
jz save_c10 ; sequences
|
|
call save_kanji ; Test if AL is a Kanji Character
|
|
; and setup up the parameter blocks
|
|
; for the INTSAVE_CHAR routine
|
|
;
|
|
; INTSAVE_CHAR is the internal entry point to the Character Save
|
|
; routine. It assumes the following:-
|
|
;
|
|
; On Entry:- AX(AL) Contains the character
|
|
; CX the new character length in bytes
|
|
; RLF_KANJI Flag is set for a Kanji Character
|
|
; RL_KANJI Contains the kanji charater
|
|
;
|
|
intsave_char:
|
|
mov bx,cx
|
|
test RL_FLAGS,RLF_INS ; Overwrite the character in the
|
|
jnz save_c50 ; buffer currently
|
|
add bx,si ; Add the current index to the character
|
|
cmp bx,RL_MAXLEN ; size and compare against the buffer len
|
|
jae bell_char ; Full ? Yes Ring dat Bell !
|
|
|
|
cmp dx,si ; Are we at the end of the line
|
|
jnz intsave_c10 ; No so check character types
|
|
push ax ! push cx
|
|
call skip_one_char ; Skip the coresponding character in
|
|
pop cx ! pop ax ; the save buffer
|
|
jmps simple_save
|
|
|
|
intsave_c10:
|
|
push ax ; Save the Input Character
|
|
call char_type ; Get the character type
|
|
mov bx,ax ; and save in BX
|
|
mov al,es:[di] ; get the byte to be replaced
|
|
call char_type ; and get its type
|
|
and ah,CHAR_SIZE ; Mask the Character SIZE attributes
|
|
and bh,CHAR_SIZE ; and check both storage and display
|
|
; sizes are the same for old and new
|
|
cmp ah,bh ; and do simple save if the character
|
|
pop ax ; Restore the input character to AX(AL)
|
|
jnz save_c30 ; type match
|
|
sub dx,cx ; Character overwritten so prevent
|
|
; Max Index being incremented
|
|
|
|
simple_save:
|
|
add si,cx ; Assume at the EOL
|
|
add dx,cx
|
|
stosb ; Save the character typed
|
|
test RL_FLAGS,RLF_KANJI ; is this a Kanji character
|
|
jz simple_s10 ; No so just output 1 character
|
|
call put_char ; and echo it to the user
|
|
mov al,byte ptr RL_KANJI+1 ; Get the high byte of the Kanji
|
|
stosb ; character save and then display it.
|
|
simple_s10:
|
|
jmp put_char
|
|
; ret
|
|
|
|
;
|
|
; The SAVE_C30 function supports the Complex overwrite conditions
|
|
; where the size of the character in memory or on the display do not
|
|
; match with those of the present incumbent. eg a SPACE character
|
|
; overwriting a TAB or a KANJI character overwriting a SPACE.
|
|
;
|
|
; To minimize the complexity of the code the character to be
|
|
; overwritten is deleted and the new character then inserted.
|
|
; This is not an optimal solution but drastically reduces the
|
|
; amount of code required.
|
|
;
|
|
save_c30:
|
|
push ax ! push cx
|
|
call deln_char
|
|
pop cx ! pop ax
|
|
cmp dx,si
|
|
jz simple_save
|
|
or RL_FLAGS,RLF_INS
|
|
call save_c50
|
|
and RL_FLAGS,not RLF_INS
|
|
ret
|
|
|
|
bell_char:
|
|
mov al,BELL
|
|
jmp write_char
|
|
;
|
|
; This code is called when INSERT mode is active and a
|
|
; character (possibly Kanji) is to be inserted in the buffer
|
|
;
|
|
; On Entry:- CX the new character length in bytes
|
|
;
|
|
save_c50:
|
|
mov bx,cx ; Save new character length
|
|
add cx,dx ; Add the current max to the character
|
|
cmp cx,RL_MAXLEN ; size and compare against the buffer len
|
|
jae bell_char ; Full ? Yes Ring dat Bell !
|
|
mov cx,bx ; Restore Character Length
|
|
cmp dx,si ; If we are at the end of the line
|
|
je simple_save ; Use the simple save code
|
|
;
|
|
; Create space in the current buffer for the new character
|
|
;
|
|
push ds
|
|
push si ! push di
|
|
mov cx,dx ! sub cx,si ; CX -> Number of bytes to move
|
|
mov di,dx ! add di,RL_BUFOFF ; DI -> End of Destination Offset
|
|
add di,bx ! dec di ; -> + Insert Char len - 1
|
|
mov si,di ! sub si,bx ; SI -> DI - Insert Char Len
|
|
push es ! pop ds ; DS == ES
|
|
std ; Make the right amount of space in
|
|
rep movsb ; the buffer
|
|
cld
|
|
pop di ! pop si
|
|
pop ds
|
|
|
|
add dx,bx ; Update the Buffer Length
|
|
stosb ; Save the New character
|
|
test RL_FLAGS,RLF_KANJI ; Check if this was a Kanji Character
|
|
jz save_c60 ; No
|
|
xchg al,ah ! stosb ; Yes Save high byte
|
|
|
|
save_c60:
|
|
mov cx,dx ! sub cx,si ; Display the updated string
|
|
add si,bx ! push si ; Save the Updated Index
|
|
mov si,di ! sub si,bx ; Get the offset of the new char
|
|
call put_string ; in the buffer and display all
|
|
pop si ; Restore the new index
|
|
xchg di,dx ; and calculate the number of BS
|
|
call calc_chars ; characters required to get back
|
|
xchg di,dx
|
|
jmp bs_out
|
|
;
|
|
; On Entry: AL First byte of Character
|
|
;
|
|
; On Exit: AX Complete Character Code
|
|
; CX Character Size Bytes
|
|
; RL_KANJI and RLF_KANJI set correctly
|
|
;
|
|
save_kanji:
|
|
and RL_FLAGS,not RLF_KANJI
|
|
mov RL_KANJI,ax ; Save the Character
|
|
call char_type ; Is this the first byte of a
|
|
test ah,CHAR_KANJI ; two byte Kanji character
|
|
mov cx,1 ; Character size in bytes
|
|
jz save_k10 ; No
|
|
or RL_FLAGS,RLF_KANJI ; Set internal Flag
|
|
call get_char ; Get the high byte and save
|
|
mov byte ptr RL_KANJI+1,al ; in the local variable
|
|
mov ax,RL_KANJI ; Get the complete character
|
|
mov cx,2 ; Character size in bytes
|
|
save_k10:
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; The following group of functions modify the flags which control
|
|
; the command line editor.
|
|
;
|
|
toggle_ins:
|
|
xor RL_FLAGS,RLF_INS ; Toggle the OverWrite/Insert
|
|
ret ; Flag
|
|
|
|
toggle_search:
|
|
and RL_FLAGS,not RLF_MATCH ; clear match bit
|
|
xor RL_FLAGS,RLF_SEARCH ; Toggle the Search on/off flag
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; This group of functions moves the cursor along the display
|
|
; as well as updating the local variables.
|
|
;
|
|
goto_bol:
|
|
test si,si ; Move the cursor to the begining of
|
|
jz goto_b10 ; the displayed line
|
|
mov di,si ; Set the buffer index to the
|
|
xor si,si ; start of the line and the current
|
|
call calc_chars ; location
|
|
call bs_out
|
|
xor si,si
|
|
mov di,RL_BUFOFF
|
|
goto_b10:
|
|
ret
|
|
|
|
next_char:
|
|
cmp si,dx
|
|
jnz next_c05 ; Treat this as "F1" when we at the
|
|
jmp copy_char ; end of the line
|
|
|
|
next_c05:
|
|
mov al,es:[di] ; Get the Offset of the next character
|
|
mov cx,1 ; the character itself and assume
|
|
call char_type ; it is 1 byte long
|
|
test ah,CHAR_KANJI ! jz next_c10
|
|
inc cx
|
|
next_c10:
|
|
xchg si,di ; Get the string offset in SI
|
|
call put_string ; display the character and
|
|
xchg si,di ; restore the register contents
|
|
add si,cx
|
|
add di,cx
|
|
ret
|
|
|
|
prev_char:
|
|
test si,si ; begining of line ?
|
|
jz prev_w30
|
|
push dx ! push si ! push di
|
|
mov si,RL_BUFOFF ; Scan from the begining of the buffer
|
|
mov dx,si ; keeping the last match in DX
|
|
prev_c10:
|
|
call char_info ; Get the character information
|
|
cmp si,di ; Stop when we get to the current
|
|
je prev_w20 ; character location
|
|
mov dx,si ; Save current location
|
|
jmps prev_c10 ; and repeat
|
|
|
|
prev_w20:
|
|
sub si,dx ; Calculate character length
|
|
push si ; save for update
|
|
|
|
sub di,RL_BUFOFF ; Convert Offset to Index
|
|
neg si ! add si,di ; Set the buffer index to the current
|
|
call calc_chars ; location and the previous character
|
|
call bs_out ; BackSpace over character
|
|
pop cx ; Restore the character size
|
|
pop di ! pop si ! pop dx
|
|
sub si,cx ; Update the Index and Pointer
|
|
sub di,cx ; variables.
|
|
prev_w30:
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; This group of functions deletes characters or groups of characters
|
|
; from the buffer.
|
|
;
|
|
|
|
delf_char:
|
|
cmp si,dx ; any chars to our right ?
|
|
jb deln_char ; yes, delete them first
|
|
jmp skip_one_char
|
|
; ret ; discard next saved char
|
|
|
|
del_eol:
|
|
mov cx,dx ! sub cx,si ; Calculate the number of bytes to
|
|
jcxz del_eol10 ; delete and jump to DELN_WORD if
|
|
add cx,di ; non zero. Convert to an offset
|
|
jmps deln_w10 ; and jmp to common code.
|
|
del_eol10:
|
|
ret
|
|
|
|
delp_char:
|
|
or si,si ! jz del_eol10 ; Ignore if the user is at the start
|
|
call back_one_char ; of the line otherwise move back one
|
|
call prev_char ; character in the line buffer
|
|
|
|
|
|
deln_char:
|
|
cmp dx,si ! jz del_eol10
|
|
mov al,es:[di] ; Get the Offset of the next character
|
|
lea cx,1[di] ; the character itself and assume
|
|
call char_type ; it is 1 byte long
|
|
test ah,CHAR_KANJI ! jz deln_w10
|
|
inc cx
|
|
; jmps deln_w10
|
|
|
|
;
|
|
; The 3 delete functions come together at this point with the standard
|
|
; register format Plus CX is the offset of the first character not to
|
|
; be deleted.
|
|
;
|
|
deln_w10:
|
|
push cx ; Save Delete Offset
|
|
xchg di,dx ; Determine the no of characters
|
|
call calc_chars ; displayed to the end of the line
|
|
xchg di,dx
|
|
mov bx,cx ; Save the Column count
|
|
pop ax ; restore the delete offset
|
|
|
|
push bx ! push bx ; Save the count twice
|
|
|
|
push si ! push di
|
|
mov cx,dx ! sub cx,si ; No of chars from old EOL
|
|
mov si,ax ; Get the Source Offset
|
|
sub ax,di ; calculate its length.
|
|
sub dx,ax ; Update the string length
|
|
|
|
sub cx,ax ; Number of chars to copy
|
|
push ds ; Move the contents of the
|
|
push es ! pop ds ; string down in memory and
|
|
rep movsb ; then update the screen image
|
|
pop ds
|
|
pop si ! pop di ; Get the current buffer offset
|
|
; Restore SWAPPED SI <-> DI
|
|
|
|
mov cx,dx ; Calculate the length of the
|
|
sub cx,di ; string and print it alll
|
|
call put_string
|
|
xchg si,di ; Restore SI and DI
|
|
|
|
jcxz deln_w20
|
|
xchg di,dx ; Calculate the number of columns
|
|
call calc_chars ; displayed
|
|
xchg di,dx
|
|
|
|
deln_w20:
|
|
pop bx ; Restore the original line length
|
|
sub bx,cx ; and calculate the number of spaces
|
|
mov cx,bx ; required to overwrite the data
|
|
call space_out
|
|
|
|
pop cx ; Finally move the cursor back to
|
|
jmp bs_out ; its correct place
|
|
|
|
|
|
|
|
|
|
;
|
|
; Delete the contents of the complete line
|
|
;
|
|
del_line:
|
|
mov RL_SAVPOS,0 ; Reset the buffer index
|
|
test dx,dx
|
|
jz del_l10
|
|
call goto_bol ; Jump to the begining of the line
|
|
mov di,dx ; calculate the number of display
|
|
call calc_chars ; columns it currently takes up
|
|
call space_out ; Overwrite with spaces
|
|
call bs_out ; Move back to the start of the line
|
|
xor si,si ; and update all the initial variables
|
|
mov dx,si
|
|
mov di,RL_BUFOFF
|
|
del_l10:
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; The following routines manipulate the SAVE Buffer data. Which
|
|
; is initialised on entry to this function.
|
|
;
|
|
; SKIP_ONE_CHAR increments the Save Buffer control variables and
|
|
; returns the number of bytes skipped in CX.
|
|
;
|
|
; On Entry: Standard Registers
|
|
;
|
|
; On Exit: AX Next Character in Buffer
|
|
; CX Character Size (Bytes)
|
|
;
|
|
skip_one_char:
|
|
xor cx,cx
|
|
mov bx,RL_SAVPOS ; Update the Save Buffer variables
|
|
cmp bx,RL_SAVMAX ; Check the current save buffer is
|
|
jae soc_20 ; valid and has not been exhausted.
|
|
; Otherwise increment the RL_SAVPOS
|
|
mov bx,offset savbuf ; pointer by one character. This
|
|
add bx,RL_SAVPOS ; means that the RL_SAVPOS can be
|
|
mov al,ds:[bx] ; incremented by 1 or 2 depending on
|
|
call char_type ; the contents of the buffer
|
|
test ah,CHAR_KANJI
|
|
jz soc_10
|
|
mov ah,ds:1[bx]
|
|
inc cx
|
|
soc_10:
|
|
inc cx
|
|
soc_20:
|
|
add RL_SAVPOS,cx
|
|
ret
|
|
;
|
|
;
|
|
; BACK_ONE_CHAR decrements the Save Buffer control variables and
|
|
; returns the number of bytes skipped in CX.
|
|
;
|
|
; On Entry: Standard Registers
|
|
;
|
|
; On Exit: RL_SAVPOS points to previous buffer char
|
|
; AX,BX,CX,DX Unknown
|
|
;
|
|
back_one_char:
|
|
push dx
|
|
mov bx,offset savbuf ; Get the Buffer address
|
|
mov cx,bx ! add cx,RL_SAVPOS ; CX is the Current location
|
|
mov dx,bx ; DX is last matching character
|
|
boc_10:
|
|
cmp bx,cx ; Have we reached the current Char
|
|
jz boc_20 ; Yes exit and update buffer
|
|
mov dx,bx ; Update last character location
|
|
mov al,ds:[bx] ; incremented by 1 or 2 depending on
|
|
call char_type ; the contents of the buffer
|
|
inc bx
|
|
test ah,CHAR_KANJI ; Increment pointer by 2 for a Kanji
|
|
jz boc_10 ; character
|
|
inc bx
|
|
jmps boc_10
|
|
|
|
boc_20:
|
|
sub dx,offset savbuf ; Calculate the character Index
|
|
mov RL_SAVPOS,dx ; and save in RL_SAVPOS
|
|
pop dx
|
|
ret
|
|
|
|
copy_char:
|
|
cmp dx,si ; If at end of line copy characters
|
|
jz copy_c5
|
|
call next_char ; Otherwise just move by 1
|
|
jmp copy_c10
|
|
copy_c5:
|
|
call skip_one_char ; Calculate Bytes to copy
|
|
jcxz copy_c10 ; Skip Update in no characters skipped
|
|
sub RL_SAVPOS,cx ; Restore the Buffer Position
|
|
jmps copy_a10 ; and copy the data
|
|
copy_c10:
|
|
ret
|
|
|
|
copy_till_char:
|
|
cmp dx,si ; Copy out if at end of line
|
|
jnz move_till_char
|
|
call skip_till_char ; Returns index to the next char
|
|
sub RL_SAVPOS,cx
|
|
jmps copy_a10
|
|
move_till_char:
|
|
mov RL_SAVPOS,si ; Start search from the current
|
|
call skip_till_char ; position
|
|
jcxz no_move ; CX=0 - dont move
|
|
move_along:
|
|
push cx
|
|
call next_char ; Shuttle along the line until
|
|
pop cx ; we reach the character
|
|
loop move_along
|
|
no_move:
|
|
ret
|
|
|
|
copy_all:
|
|
mov cx,RL_SAVMAX ; Calculate the number of bytes to
|
|
sub cx,RL_SAVPOS ; copy from the buffer.
|
|
copy_a10:
|
|
cmp cx,0 ; do we have nothing to copy
|
|
jle copy_a30 ; (or less than nothing..)
|
|
|
|
push RL_FLAGS ; Save State flags and prevent
|
|
or RL_FLAGS,RLF_INS ; SAVPOS being modified
|
|
copy_a20:
|
|
push cx
|
|
and RL_FLAGS,not RLF_KANJI
|
|
call skip_one_char ; Return the next character and its
|
|
cmp cx,1
|
|
jz copy_a25 ; size in bytes
|
|
mov RL_KANJI,ax ; Save the Kanji Character and
|
|
or RL_FLAGS,RLF_KANJI ; set the control flag
|
|
pop bx
|
|
dec bx
|
|
push bx ; Decrement the Loop Count
|
|
|
|
copy_a25:
|
|
call intsave_char ; Save the character
|
|
pop cx ; and repeat till all bytes have
|
|
loop copy_a20 ; been copied
|
|
pop RL_FLAGS ; Restore State Flags
|
|
copy_a30:
|
|
ret
|
|
|
|
skip_till_char:
|
|
call get_char ; Get the first character
|
|
call save_kanji ; Setup RL_KANJI etc.
|
|
push dx
|
|
call skip_one_char ; don't match on 1st char
|
|
mov dx,cx ; remember we've skipped 1st char
|
|
jcxz stc_40 ; buffer exhausted
|
|
stc_10:
|
|
call skip_one_char ; Get the Next Character
|
|
jcxz stc_40 ; Buffer exhausted
|
|
add dx,cx ; Update the Total Byte Count
|
|
cmp cx,2 ! jz stc_20 ; Was this a Kanji Character
|
|
test RL_FLAGS,RLF_KANJI ; No but are we looking for one ?
|
|
jnz stc_10 ; Yes so get the next character
|
|
cmp al,byte ptr RL_KANJI ; Have we got a matching character ?
|
|
jnz stc_10 ; No so look again
|
|
jmps stc_30 ; Return Sucess
|
|
|
|
stc_20: ; Kanji Character in Buffer
|
|
test RL_FLAGS,RLF_KANJI ; Are we looking for a Kanji Char
|
|
jz stc_10 ; No so try again
|
|
cmp ax,RL_KANJI ; Check the character and repeat
|
|
jnz stc_10 ; if they donot match
|
|
|
|
stc_30: ; Character Match
|
|
sub dx,cx ; Correct the Total Byte Count
|
|
sub RL_SAVPOS,cx ; point to the matching char
|
|
xchg cx,dx ; and return the Match Count
|
|
pop dx
|
|
ret
|
|
|
|
stc_40: ; No Match
|
|
sub RL_SAVPOS,dx ; Restore RL_SAVPOS to orginal value
|
|
xor cx,cx ; and return 0000 characters skipped
|
|
pop dx
|
|
ret
|
|
|
|
;
|
|
; Update the Save buffer with the contents of the users
|
|
; line buffer.
|
|
;
|
|
; On Entry: ES:DI -> Current location in Buffer
|
|
; DX No. of bytes in buffer
|
|
;
|
|
; On Exit: Update RL_SAVMAX, RL_SAVPOS, RL_SAVBUF
|
|
;
|
|
save_line:
|
|
xor ax,ax
|
|
mov RL_SAVPOS,ax
|
|
mov RL_SAVMAX,ax
|
|
mov cx,dx ; Current Line Length
|
|
jcxz save_l10
|
|
cmp cx,savbuf_size ; clip the amount saved
|
|
jb save_l5 ; to be a maximum of
|
|
mov cx,savbuf_size ; the save buffer size
|
|
save_l5:
|
|
mov RL_SAVMAX,cx ; Set the Save Data Length
|
|
push ds ! push es
|
|
push si ! push di
|
|
|
|
push ds ! pop es
|
|
lds si,RL_BUFPTR
|
|
mov di,offset savbuf
|
|
rep movsb ; save the data
|
|
pop di ! pop si
|
|
pop es ! pop ds
|
|
save_l10:
|
|
; ret
|
|
|
|
ignore_char:
|
|
ret
|
|
|
|
mem_line: ;; JFL save from beginning of line
|
|
call save_line
|
|
jmp goto_bol
|
|
; ret
|
|
|
|
|
|
eof_char: ;; JFL make F6 return a CTL Z
|
|
mov al,01Ah
|
|
mov cx,1
|
|
jmp intsave_char
|
|
; ret
|
|
|
|
ctlat_char: ;; JFL make F7 return a CTL @
|
|
mov al,0h
|
|
mov cx,1
|
|
jmp intsave_char
|
|
; ret
|
|
|
|
|
|
eject
|
|
;
|
|
; CHAR_TYPE get the next character from the buffer ES:SI and returns
|
|
; its type in AH using the equates CHAR_????. The character is returned
|
|
; in AL.
|
|
;
|
|
;
|
|
;
|
|
char_type:
|
|
mov ah,CHAR_SPACE or CHAR_STD ; WhiteSpace
|
|
cmp al,' ' ! jz char_t100
|
|
mov ah,CHAR_TAB ; Tab Character
|
|
cmp al,TAB ! jz char_t100
|
|
mov ah,CHAR_ALPHAN or CHAR_STD
|
|
cmp al,CTLU ! jz char_t100 ; Control-U and Control-T are treated
|
|
cmp al,CTLT ! jz char_t100 ; as normal characters
|
|
mov ah,CHAR_CTL ; Control Character
|
|
cmp al,' ' ! jb char_t100
|
|
|
|
mov ah,CHAR_ALPHAN or CHAR_STD
|
|
cmp al,'0' ! jb char_t90 ; Return SYMBOL
|
|
cmp al,'9' ! jbe char_t100 ; Return AlphaNumeric
|
|
cmp al,'A' ! jb char_t90 ; Return Symbol
|
|
cmp al,'Z' ! jbe char_t100 ; Return AlphaNumeric
|
|
cmp al,'a' ! jb char_t90 ; Return Symbol
|
|
cmp al,'z' ! jbe char_t100 ; Return AlphaNumeric
|
|
cmp al,80h ! jb char_t90 ; Return Symbol
|
|
|
|
mov ah, CHAR_KANJI ; assume character is 16 bits
|
|
call dbcs_lead ; is byte a DBCS lead?
|
|
je char_t100 ; yes - done
|
|
char_t90:
|
|
mov ah,CHAR_OTHER or CHAR_STD ; no - Normal Character Symbol
|
|
|
|
char_t100:
|
|
ret
|
|
|
|
|
|
|
|
|
|
|
|
;
|
|
; CHAR_INFO will return various information about the character
|
|
; at ES:SI
|
|
;
|
|
; On Entry: ES:SI Character Pointer
|
|
; BX Current Column No.
|
|
; CX Byte Scan Count
|
|
;
|
|
; On Exit: ES:SI Points to the next Character
|
|
; BX Updates Column No.
|
|
; CX Updates Byte Scan Count
|
|
; AH Character type Flags
|
|
; AL First byte of Character
|
|
char_info:
|
|
lods es:al
|
|
call char_type ; Test the character type and assume
|
|
inc bx ; it will take 1 Screen location
|
|
test ah,CHAR_ONECOL
|
|
jnz char_i20
|
|
|
|
inc bx ; Now check for the Control Characters
|
|
test ah,CHAR_CTL ; which take up 2 cols
|
|
jnz char_i20
|
|
|
|
test ah,CHAR_KANJI ; If this was the first byte of a
|
|
jz char_i10 ; KANJI character then skip the
|
|
inc si ! dec cx ; next byte
|
|
jmps char_i20
|
|
|
|
char_i10:
|
|
push ax ; Save AX and calculate the number
|
|
dec bx ! dec bx ; of screen locations that this TAB
|
|
mov ax,bx ; character will use based on the fact
|
|
and ax,7 ; BX contains the current column
|
|
neg ax ! add ax,8
|
|
add bx,ax
|
|
pop ax
|
|
|
|
char_i20:
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; CALC_CHARS calculates the number of character locations used
|
|
; on the screen to display a particular sub-string of the current
|
|
; buffer. This routine takes account of the Kanji, Control and TAB
|
|
; characters.
|
|
;
|
|
; On Entry: SI Start Buffer Index
|
|
; DI End Buffer Index
|
|
;
|
|
; On Exit: CX Count
|
|
;
|
|
calc_chars:
|
|
push bx
|
|
push si ! push di
|
|
mov bx,RL_INICOL ; Get the initial Column
|
|
sub di,si ; DI = Sub-string length bytes
|
|
mov cx,si ; Use the Start Index for the
|
|
mov si,RL_BUFOFF ; initial count and scan from the
|
|
jcxz calc_c20 ; start of the buffer
|
|
|
|
calc_c10:
|
|
call char_info
|
|
loop calc_c10
|
|
|
|
calc_c20:
|
|
mov cx,di ; Sub-String Length
|
|
mov di,bx ; Current Column position
|
|
|
|
calc_c30:
|
|
call char_info
|
|
loop calc_c30
|
|
|
|
sub bx,di
|
|
mov cx,bx
|
|
pop di ! pop si
|
|
pop bx
|
|
ret
|
|
|
|
eject
|
|
;
|
|
; The following functions are purely Low level character output
|
|
; functions.
|
|
;
|
|
space_out: ; Write CX Space characters to the
|
|
mov al,' ' ; Output handle
|
|
jmps block_out
|
|
|
|
bs_out:
|
|
mov al,CTLH ; Write CX BackSpace characters to
|
|
;; jmps block_out ; Output Handle
|
|
|
|
block_out:
|
|
jcxz block_o20
|
|
push cx
|
|
block_o10:
|
|
call write_char ; output this character
|
|
loop block_o10
|
|
pop cx
|
|
block_o20:
|
|
ret
|
|
|
|
;
|
|
; Display CX characters from the string at ES:SI
|
|
;
|
|
put_string:
|
|
jcxz puts_s20
|
|
push cx ! push si
|
|
put_s10:
|
|
push cx
|
|
lods es:al
|
|
call put_char
|
|
pop cx
|
|
loop put_s10
|
|
pop si ! pop cx
|
|
puts_s20:
|
|
ret
|
|
|
|
;
|
|
; Display the character in AL
|
|
;
|
|
put_char:
|
|
cmp al,' ' ! jae write_char ; skip if it's printable
|
|
cmp al,CTLT! je write_char ; Control-T and Control-U are treated
|
|
cmp al,CTLU! je write_char ; like normal Characters.
|
|
cmp al,TAB ! je write_char ; skip if it's TAB
|
|
or al,040h ; Convert Character to Uppercase
|
|
push ax ; save it
|
|
mov al,'^' ; display the character
|
|
call write_char ; in ^X format
|
|
pop ax
|
|
write_char:
|
|
push es
|
|
push dx
|
|
push cx
|
|
push si
|
|
push di
|
|
push ax ; char on stack
|
|
mov bx,RL_OUTPUT ; Output AL to the OUTPUT Handle
|
|
push ss ! pop es ; ES:DX -> Character Buffer
|
|
mov si,sp ; buffer offset
|
|
mov cx,1 ; character count
|
|
call cooked_write ; Write Character
|
|
pop ax
|
|
pop di
|
|
pop si
|
|
pop cx
|
|
pop dx
|
|
pop es
|
|
ret
|
|
;
|
|
; Read 1 a character from RL_INPUT saving all the vital registers
|
|
; from corruption. If the first character is the ESCAPE character
|
|
; set AH to TRUE and read the next byte. Otherwise AH is FALSE
|
|
;
|
|
get_char:
|
|
push ds
|
|
push es
|
|
push dx
|
|
push si
|
|
push di
|
|
|
|
call get_dseg ; point at pcmode data
|
|
lds si,con_device ; DS:SI -> current console device
|
|
test ds:DH_ATTRIB[si],DA_IOCTL ; test bit 14: IOCTL bit
|
|
jz get_c05 ; error if IOCTL not supported
|
|
sub sp,RH_SIZE ; reserve this many words on the stack
|
|
mov bx,sp ; SS:BX -> request packet
|
|
push ss ! pop es ; ES:BX -> request packet
|
|
lea dx,RL_FLAGS ; point at flags
|
|
mov es:RH_CMD[bx],CMD_OUTPUT_IOCTL
|
|
mov es:RH_LEN[bx],RH4_LEN
|
|
mov es:RH4_BUFOFF[bx],dx ; set up for a normal
|
|
mov es:RH4_BUFSEG[bx],ss ; IOCTL read/write
|
|
mov es:RH4_COUNT[bx],WORD
|
|
call device_driver ; execute the command
|
|
add sp,RH_SIZE ; reclaim the stack
|
|
get_c05:
|
|
|
|
call get_dseg ; point at pcmode data
|
|
mov bx,RL_INPUT ; BX = input stream
|
|
call cmdline_read ; get a character
|
|
|
|
mov ah,FALSE ; Assume this is NOT the Escape
|
|
cmp al,esc_char ; character and set high byte of the
|
|
jnz get_c10 ; match word to FALSE
|
|
|
|
call raw_read ; read the second byte of the escape
|
|
mov ah,ESC_CODE ; sequence, setting high byte to ESC
|
|
get_c10:
|
|
pop di
|
|
pop si
|
|
pop dx
|
|
pop es
|
|
pop ds
|
|
ret
|
|
|
|
PCM_RODATA CSEG WORD
|
|
|
|
EDIT_CNTRL equ cs:word ptr 0[bx] ; Character and Esc Flag
|
|
EDIT_FUNC equ cs:word ptr 2[bx] ; Edit Function Address
|
|
EDIT_LEN equ 4 ; Edit Table Entry Size
|
|
|
|
esc_char db 0 ; Command Line Editor Escape Character
|
|
edit_size dw (offset edit_end - edit_table)/EDIT_LEN
|
|
|
|
edit_table db CR ! db NESC_CODE ! dw ret_string
|
|
db LF ! db NESC_CODE ! dw ignore_char
|
|
db CTLH ! db NESC_CODE ! dw delp_char
|
|
db DEL ! db NESC_CODE ! dw delf_char
|
|
|
|
db ESC ! db NESC_CODE ! dw del_line
|
|
db ';' ! db ESC_CODE ! dw copy_char ; Function 1
|
|
db '<' ! db ESC_CODE ! dw copy_till_char ; Function 2
|
|
db '=' ! db ESC_CODE ! dw copy_all ; Function 3
|
|
db '>' ! db ESC_CODE ! dw skip_till_char ; Function 4
|
|
db '?' ! db ESC_CODE ! dw mem_line ; Function 5
|
|
|
|
db '@' ! db ESC_CODE ! dw eof_char ; Function 6
|
|
db 'A' ! db ESC_CODE ! dw ctlat_char ; Function 7
|
|
db 'B' ! db ESC_CODE or DISABLE ! dw match_cmd ; Function 8
|
|
|
|
db 'R' ! db ESC_CODE ! dw toggle_ins ; Insert
|
|
db 'S' ! db ESC_CODE ! dw delf_char ; Delete
|
|
db 'K' ! db ESC_CODE or DISABLE ! dw prev_char ; Left Arrow
|
|
db 'M' ! db ESC_CODE or DISABLE ! dw next_char ; Right Arrow
|
|
; When advanced editing is disabled the match for Left/Right arrows will fall
|
|
; through to here
|
|
db 'K' ! db ESC_CODE ! dw delp_char ; Left Arrow - compat
|
|
db 'M' ! db ESC_CODE ! dw copy_char ; Right Arrow - compat
|
|
;
|
|
; Extended functions from here on
|
|
;
|
|
db 'C' ! db ESC_CODE or DISABLE ! dw del_cur_history_buffer ; Func 9
|
|
db 'D' ! db ESC_CODE or DISABLE ! dw del_history_buffers ; Func 10
|
|
db 'G' ! db ESC_CODE or DISABLE ! dw goto_bol ; Home
|
|
db 'O' ! db ESC_CODE or DISABLE ! dw goto_eol ; End
|
|
db 't' ! db ESC_CODE or DISABLE ! dw next_word ; Control Right Arrow
|
|
db 's' ! db ESC_CODE or DISABLE ! dw prev_word ; Control Left Arrow
|
|
|
|
|
|
db CTLV ! db NESC_CODE or DISABLE ! dw toggle_ins
|
|
db CTLQ ! db NESC_CODE or DISABLE ! dw goto_bol
|
|
db CTLW ! db NESC_CODE or DISABLE ! dw goto_eol
|
|
db CTLR ! db NESC_CODE or DISABLE ! dw match_cmd
|
|
db CTLD ! db NESC_CODE or DISABLE ! dw next_char
|
|
db CTLS ! db NESC_CODE or DISABLE ! dw prev_char
|
|
db CTLF ! db NESC_CODE or DISABLE ! dw next_word
|
|
db CTLA ! db NESC_CODE or DISABLE ! dw prev_word
|
|
db CTLG ! db NESC_CODE or DISABLE ! dw deln_char
|
|
db CTLT ! db NESC_CODE or DISABLE ! dw deln_word
|
|
db CTLY ! db NESC_CODE or DISABLE ! dw del_line
|
|
db CTLB ! db NESC_CODE or DISABLE ! dw del_bol
|
|
db CTLK ! db NESC_CODE or DISABLE ! dw del_eol
|
|
|
|
db 'I' ! db ESC_CODE or DISABLE ! dw ignore_char ; PageUP
|
|
db 'Q' ! db ESC_CODE or DISABLE ! dw ignore_char ; PageDown
|
|
db 'H' ! db ESC_CODE or DISABLE ! dw prev_cmd ; Up Arrow
|
|
db 'P' ! db ESC_CODE or DISABLE ! dw next_cmd ; Down Arrow
|
|
db CTLE ! db NESC_CODE or DISABLE ! dw prev_cmd
|
|
db CTLX ! db NESC_CODE or DISABLE ! dw next_cmd
|
|
db CTLUB ! db NESC_CODE or DISABLE ! dw toggle_search ; Default search mode
|
|
edit_end rb 0
|
|
|
|
|
|
PCMODE_DATA DSEG WORD
|
|
|
|
extrn con_device:dword ; Current Console Device
|
|
extrn column:byte ; Console Cursor Location
|
|
|
|
savbuf_size equ 128
|
|
|
|
extrn savbuf:byte ; fixed location in DOS data area
|
|
|
|
extrn cle_state:word ; command line editing state
|
|
|
|
end
|
|
|