📄 cio.a86
字号:
func0B:
;
; Entry:
; AH == 0Bh
; Exit:
; AL == 0FFh if char available
; == 00h otherwise
;
mov bx,STDIN
call cooked_status ; Get the current handle status
mov al,0FFh ; Assume that the handle is ready
jz f0B_exit ; and return 0FFh in AL
mov al,00 ; Not Ready
f0B_exit:
jmps funcICexit ; exit thru incomplete char support
; *****************************
; *** DOS Function 0C ***
; *** Flush and Execute ***
; *****************************
;
Public func0C
func0C:
;
; Entry:
; AH == 0Ch
; AL == function to execute: 1,6,7,8 or A
; Exit:
; AL = 0 if function in AL is invalid
;
push ax ; save sub-function
mov bx,STDIN ; Is this Standard Input Handle a
call is_device ; file or device. Do not flush the
jc f0C_20 ; buffer contents for a FILE
f0C_10:
call hndl_instat ; check if any characters are left
jnz f0C_20 ; and quit when buffer empty
call raw_read ; read the character
jmps f0C_10 ; loop till the buffer is empty
f0C_20:
pop ax
cmp al,01h ! je al_ok ; is legal for this command
cmp al,0ah ! je al_ok
cmp al,06h ! jb al_nogo
cmp al,08h ! ja al_nogo
al_ok: ; Valid function so now execute
call reload_registers ; all register reloaded as per entry
mov ah,al ; Get the requested sub-function in AH
jmp int21_func ; execute the function
al_nogo: ; Illegal command to execute
xor ax,ax ; from this function so return error
ret
eject
;
; BREAK_CHECK checks for a CNTRL-C and is called by functions 01h to
; 0Ch. Or by the entry code if the break flag is non zero.
;
Public break_check
break_check:
cmp indos_flag,01 ; Skip the check if we are
jnz break_c15 ; already in the emulator
push ax
push es
push si
les si,con_device
call device_instat ; get the input status
pop si
pop es
jnz break_c10 ; No Character Ready
cmp al,CTLC ; Is the character a Control-C
jz break_c20 ; Yes
break_c10:
pop ax
break_c15:
ret
break_c20: ; The User has Typed Control-C so flush
mov bx,0FFFFh ; input buffer (FFFF=con_device)
call char_get
go_int23:
push cs ! pop es ; ES:DX -> Character Buffer
mov si,offset cntrl_c_msg ; Message Offset
mov cx,length cntrl_c_msg ; Message Length
call stdout_cooked_write ; write the ^C String to console
;
; Prepare to execute an Interrupt 23 (Break Check) and process
; the return values. If the called routine returns with an IRET
; or with a RETF and the carry flag reset continue the function
; otherwise Abort.
;
mov es,current_psp ; Get the Entry SS and SP
mov ax,PSP_USERSP ; Get the Users Stack Pointer
add ax,18 - 2 ; Compensate for the User Registers
mov break_sp,ax ; and save for RETF check
cli
dec indos_flag ; Exit the PCDOS emulator
mov ss,PSP_USERSS ; Switch to the Users Stack
mov sp,PSP_USERSP ; and Restore the registers
POP$DOS ; Update the registers then
; set the flags and return
; to the user
clc ; Default to continue function
int 23h ; Call the Break Handler
cli ; Check the Flag State
jnc do23_10 ; If CARRY then Abort this process
call get_dseg ; Get our data segment
mov exit_type,TERM_BREAK ; Force EXIT_TYPE to TERM_BREAK
mov ax,4C00h ; "Good-Bye Cruel World"
jmps do23_20
do23_10:
push ds ; Otherwise restart the aborted func
call get_dseg
cmp sp,break_sp
pop ds ; Restore the the USER DS correct
jz do23_30 ; Did we Use a RETF or Not
do23_20:
add sp,2 ; Yes so correct the stack pointer
do23_30: ; and restart the aborted function
jmp int21_entry ; re-start the function call
eject
;
; cooked_status is called on input or output and looks for live keys ^C,^P,^S.
; If any of these are found they are dealt with.
; If ^P is encountered it is swallowed.
; If ^C is encountered we always do an Int23.
; If ^S is pressed we swallow it, and the next character (checking for ^C, but
; not for ^P), then say a character is ready.
; Note that this can lead to status calls (func0B) hanging inside the OS,
; or the return of ^S characters from input calls (func01), but this is
; intentional.
;
cooked_status:
;-------------
; check input
; On Entry:
; BX = handle to check
; On Exit:
; ZF set if character available
; AL = character
; AH = RHS_IC
;
call break_check ; check for a ^C on console
call char_check ; is there a character ready
jnz cooked_s50 ; no so keep scanning
cmp last_key_ext,0 ; was last char an zero ?
mov last_key_ext,0 ; (clear flag for next time)
jne cooked_s40 ; skip ^P,^S,^C checks if so
cmp al,CTLP ; has the user typed ^P
jne cooked_s10 ; flush the buffer and
xor cio_state,CIO_CTLP ; toggle ^P flag
call char_get ; flush the character from buffer
call open_or_close_prn ; open/close printer device
test ax,ax ; ZF clear, ie. no char available
jmps cooked_s50
cooked_s10:
cmp al,CTLC
jnz cooked_s30 ; has the user typed ^C
call char_get ; so get the RAW character
cooked_s20:
jmp go_int23 ; and terminate the function
cooked_s30:
cmp al,CTLS ; pause if the user has typed
jnz cooked_s40 ; a ^S
call char_get ; remove ^S and resume when
call raw_read_wait ; the next character is typed
cmp al,CTLC
je cooked_s20 ; has the user typed ^C
cooked_s40:
cmp al,0
jne cooked_s45
mov last_key_ext,1
cooked_s45:
cmp ax,ax ; ZF set, ie. char available
cooked_s50:
ret
eject
;
; The COOKED, CMDLINE and RAW Read functions are basically the same
; except in their treatment of 'live' characters ^C,^P, and ^S.
; COOKED will look for and act upon all three live characters.
; CMDLINE will look for and act upon ^C and ^P, but ^S will be returned
; so we can use it as a line editing key.
; RAW will not check for any live keys.
;
public cmdline_read, raw_read ; for CMDLINE.PCM
cmdline_read_wait: ; Waiting for a device to become
call idle_dev ; ready. So call IDLE routines to
; put the processor to sleep.
cmdline_read:
call break_check ; check for a ^C on console
call char_check ; is there a character ready
jnz cmdline_read_wait ; no so keep scanning
cmp al,CTLS ; if the user has typed ^S
jne cooked_read ; we have to do a raw read
; jmps raw_read ; else we do a cooked read
raw_read_wait: ; Waiting for a device to become
call idle_dev ; ready. So call IDLE routines to
; put the processor to sleep.
raw_read:
call char_check ; Is there a character Ready
jnz raw_read_wait ; loop until character available
jmps char_get
cooked_read_wait: ; Waiting for a device to become
call idle_dev ; ready. So call IDLE routines to
; put the processor to sleep.
cooked_read:
call break_check ; check for a ^C on console
call cooked_status ; check for a ^S,^P,^C on handle BX
jnz cooked_read_wait ; wait until char is available
; jmps char_get ; else get the character
char_get:
push es ! push ax ; Input one character and
mov dx,sp ; return it in AL
call is_device ; Does this handle refer to a device
mov cx,1
jc char_get30 ; if it's a device then
call device_read ; use device_read
char_get20:
pop ax ! pop es
ret
char_get30:
; We are redirected, so call to the FDOS to get a character
push ss ! pop es ; EX:DX -> character to read
mov ah,MS_X_READ ; call the FDOS to do all
call dos_entry ; the hard work
jmps char_get20
eject
stdout_cooked_write:
mov bx,STDOUT ; output to the console device
; jmp cooked_write
;
; The COOKED_WRITE routine will expand TABS etc in the string
; passed passed by the calling routine.
;
; On Entry:
; ES:SI Buffer Address
; CX Character Count
; BX Output Handle
; On Exit:
; AL = last char written
;
Public cooked_write
cooked_write:
push es
push bx
mov ah,cio_state ; get CIO_CTLP status
or ah,CIO_RAW+CIO_HANDLE ; assume we will want raw handle output
mov al,bl
test byte ptr remote_call+1,DHM_FCB/100h
jnz cook_w03
mov es,current_psp ; get our PSP
cmp bx,PSP_XFNMAX ; range check our handle
jae cook_w05
les di,PSP_XFTPTR
mov al,es:byte ptr [bx+di] ; AL = Internal File Handle
cook_w03:
call ifn2dhndl ; ES:BX -> DHNDL_
jc cook_w05 ; skip if bad handle
mov dx,es:DHNDL_WATTR[bx] ; get handle attributes
and dx,DHAT_DEV+DHAT_CIN+DHAT_COT+DHAT_BIN+DHAT_REMOTE
cmp dx,DHAT_DEV+DHAT_CIN+DHAT_COT+DHAT_BIN
je cook_w04 ; accept binary console device
cmp dx,DHAT_DEV+DHAT_CIN+DHAT_COT
jne cook_w05 ; skip if not cooked console device
and ah,not CIO_RAW ; we want cooked output
cook_w04:
les bx,es:DHNDL_DEVPTR[bx] ; its the console - but is it FAST ?
test es:DH_ATTRIB[bx],DA_SPECIAL
jz cook_w05 ; skip if not
and ah,not CIO_HANDLE ; don't use handle functions
cook_w05:
pop bx
pop es
jcxz cook_w80
cook_w10:
lods es:al ; Read the next character
cmp al,DEL ! je cook_w60 ; DEL is a NON Printing Character
cmp al,' ' ! jae cook_w50 ; Space and Above are Normal
cmp al,LF ! je cook_w60 ; Just print LineFeeds
cmp al,ESC ! je cook_w60 ; Just print Escape
cmp al,BELL! je cook_w60 ; Just ring the Bell
cmp al,CR ! jne cook_w20 ; CR zeros the column number
mov column,0
mov char_count,1 ; check for ^S etc NOW
jmps cook_w60
cook_w20:
cmp al,CTLH ! jne cook_w30 ; BackSpace decrements the
dec column ; column count by one
jmps cook_w60
cook_w30:
cmp al,TAB ! jne cook_w60 ; is it a TAB ?
cook_w40:
mov al,' ' ; spaces
call cooked_out ; output a space char
inc column
test column,7 ; are we at a TAB stop yet ?
jnz cook_w40
jmps cook_w70
cook_w50:
inc column ; Update the column count and
cook_w60:
call cooked_out ; output the character
cook_w70:
loop cook_w10 ; onto the next character
cook_w80:
ret
cooked_out:
; On Entry:
; AH = handle status
; AL = character
; BX = handle
; On Exit:
; AX, BX, CX, ES:SI preserved
;
dec char_count ; time to check keyboard input ?
jz cooked_o10 ; no, skip status check
test ah,CIO_HANDLE+CIO_CTLP ; is it complicated ?
jnz cooked_o10
int 29h ; This device supports FAST console
ret
cooked_o10:
push es
push ax
push cx
push si
call hndl_write ; display the character
test ah,CIO_CTLP ; Check for Printer Echo
jz cooked_o20 ; Off so No Echo
push bx ; Save Output Handle
mov bx,STDPRN ; and output the same data to the
call hndl_write ; to the Printer Handle
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -