mirror of
https://github.com/SEPPDROID/DR-DOS-OpenDOS.git
synced 2025-10-22 07:54:28 +00:00
1830 lines
46 KiB
Plaintext
1830 lines
46 KiB
Plaintext
; File : $MISC.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$
|
|
; MISC.A86 1.29 94/11/30 14:40:17
|
|
; fixed error return for function 6602
|
|
; MISC.A86 1.28 94/07/13 15:31:04
|
|
; Pass name to share on Int21/5D02 (close file by name)
|
|
; MISC.A86 1.27 93/11/29 14:18:16
|
|
; Fix bug in get extended country info if not current country
|
|
; MISC.A86 1.25 93/11/19 17:00:14
|
|
; If 21/38 get country info fails for current codepage, try any codepage
|
|
; MISC.A86 1.24 93/11/16 15:57:08
|
|
; int 21/5D06 clears CY flag
|
|
; MISC.A86 1.23 93/10/21 19:31:16
|
|
; Move Int 21/5D03+5D04 support (close all files by machine/psp) into share
|
|
; MISC.A86 1.22 93/10/18 17:41:45
|
|
; fix for >255 open files (PNW Server)
|
|
; MISC.A86 1.21 93/09/03 20:28:57
|
|
; Add intl/dbcs support for int 21/6523 (query yes/no char)
|
|
; MISC.A86 1.20 93/07/26 20:42:13
|
|
; Seperate int21/3306
|
|
; MISC.A86 1.12 93/03/05 18:12:33
|
|
; Fix DS corruption for NLSFUNC calls
|
|
; ENDLOG
|
|
;
|
|
|
|
VALID_SIG equ 0EDC1h
|
|
|
|
include pcmode.equ
|
|
include i:msdos.equ
|
|
include i:mserror.equ
|
|
include i:psp.def
|
|
include i:driver.equ
|
|
include i:char.def
|
|
include i:country.def
|
|
include i:doshndl.def
|
|
include i:redir.equ
|
|
include i:fdos.equ
|
|
|
|
NLSFUNC equ TRUE
|
|
|
|
;
|
|
GLOBAL_DATA DSEG WORD
|
|
extrn default_country:byte
|
|
extrn Ucasetbl:word
|
|
extrn FileUcasetbl:word
|
|
extrn FileCharstbl:word
|
|
extrn Collatingtbl:word
|
|
extrn DBCS_tbl:word
|
|
extrn NoYesChars:byte
|
|
extrn info1_len:abs
|
|
extrn info2_len:abs
|
|
extrn info4_len:abs
|
|
extrn info5_len:abs
|
|
extrn info6_len:abs
|
|
extrn info7_len:abs
|
|
extrn dos_version:word
|
|
extrn country_filename:byte
|
|
|
|
|
|
PCM_CODE CSEG BYTE
|
|
extrn dbcs_lead:near
|
|
extrn device_write:near ; Write to a Character Device
|
|
extrn device_read:near ; Read from a Character Device
|
|
extrn dos_entry:near
|
|
extrn error_exit:near
|
|
extrn error_ret:near
|
|
extrn func5F_common:near
|
|
extrn get_dseg:near
|
|
extrn valid_drive:near
|
|
extrn ifn2dhndl:near
|
|
extrn int21_func:near
|
|
extrn invalid_function:near
|
|
extrn patch_version:word
|
|
extrn reload_registers:near
|
|
extrn reload_ES:near
|
|
extrn return_AX_CLC:near
|
|
extrn return_BX:near
|
|
extrn return_CX:near
|
|
extrn return_DX:near
|
|
extrn toupper:near
|
|
extrn xlat_xlat:word
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 34 ***
|
|
; *** Get The Indos Flag ***
|
|
; *****************************
|
|
Public func34
|
|
func34:
|
|
mov bx,offset indos_flag
|
|
; jmp return_DSBX_as_ESBX ; return ES:BX -> indos flag
|
|
|
|
Public return_DSBX_as_ESBX
|
|
|
|
return_DSBX_as_ESBX:
|
|
;-------------------
|
|
; On Entry:
|
|
; DS:BX to be returned to caller in ES:BX
|
|
; On Exit:
|
|
; ES/DI trashed
|
|
;
|
|
les di,ss:int21regs_ptr
|
|
mov es:reg_ES[di],ds
|
|
mov es:reg_BX[di],bx
|
|
ret
|
|
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 52 ***
|
|
; *** Get Internal Data ***
|
|
; *****************************
|
|
;
|
|
;
|
|
Public func52
|
|
func52:
|
|
mov bx,offset func52_data
|
|
jmps return_DSBX_as_ESBX ; return ES:BX -> internal data
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 5D ***
|
|
; *** Private DOS Func ***
|
|
; *****************************
|
|
;
|
|
;
|
|
Public func5D
|
|
func5D:
|
|
if DOS5
|
|
cmp al,7
|
|
jae f5d_05
|
|
mov si,dx ; ES:SI -> callers structure
|
|
mov bx,es:word ptr 20[si]
|
|
mov ss:owning_psp,bx ; update PSP from there
|
|
cmp WindowsHandleCheck,26h
|
|
jne f5D_05 ; check if Windows is running
|
|
mov bx,es:word ptr 18[si]
|
|
mov ss:machine_id,bx ; no, update machine_id
|
|
f5D_05:
|
|
else
|
|
push ds
|
|
push es ! pop ds ; restore users DS
|
|
callf ss:win386_remote_machine
|
|
pop ds
|
|
endif
|
|
cbw ; zero AH for valid functions
|
|
xchg ax,bx ; sub function in BX
|
|
|
|
cmp bx,func5D_ftl ; Assume Illegal Subfunction
|
|
jb f5D_10 ; check that it is a valid
|
|
mov bx,func5D_ftl ; subfunction
|
|
f5D_10:
|
|
shl bx,1
|
|
push func5D_ft[bx] ; save function address
|
|
shr bx,1
|
|
xchg ax,bx ; restore BX
|
|
ret ; go to function
|
|
|
|
f5D_msnet:
|
|
mov ax,I2F_REDIR_5D ; magic number to redirect
|
|
jmp func5F_common ; calls to extentions
|
|
;
|
|
;
|
|
; The registers for some of the following sub-functions are passed
|
|
; in the following structure.
|
|
;
|
|
RDC_AX equ es:word ptr 00[di] ; User AX
|
|
RDC_BX equ es:word ptr 02[di] ; User BX
|
|
RDC_CX equ es:word ptr 04[di] ; User CX
|
|
RDC_DX equ es:word ptr 06[di] ; User DX
|
|
RDC_SI equ es:word ptr 08[di] ; User SI
|
|
RDC_DI equ es:word ptr 10[di] ; User DI
|
|
RDC_DS equ es:word ptr 12[di] ; User DS
|
|
RDC_ES equ es:word ptr 14[di] ; User ES
|
|
RDC_RES equ es:word ptr 16[di] ; Remote Machine ID (High Word)
|
|
RDC_UID equ es:word ptr 18[di] ; Remote Machine ID (Low Word)
|
|
RDC_PID equ es:word ptr 20[di] ; Process ID
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 5D00 ***
|
|
; *** Remote DOS Call ***
|
|
; *****************************
|
|
;
|
|
;
|
|
f5D00:
|
|
mov remote_call,0ffh ; set remote op flag
|
|
push es
|
|
les di,int21regs_ptr ; stack image the copy registers
|
|
pop ds
|
|
mov cx,6
|
|
rep movsw ; Copy AX, BX, CX, DX, SI, DI
|
|
inc di ! inc di ; Skip BP in the destination
|
|
movsw ! movsw ; finally copy DS and ES
|
|
push ss ! pop ds ; DS -> PCMDSEG
|
|
call reload_registers ; load up the new registers
|
|
jmp int21_func ; then execute that function
|
|
|
|
; *****************************
|
|
; *** DOS Function 5D01 ***
|
|
; *** Commit all files ***
|
|
; *****************************
|
|
;
|
|
f5D01:
|
|
;-----
|
|
; We are being asked to commit all files to disk
|
|
; By pretending to be FCB's we force use of IFN's, and we commit all possible
|
|
; files in the range 0-255, ignoring errors from unopened handles.
|
|
;
|
|
mov remote_call,DHM_FCB ; pretend to be FCB, forces use of IFN
|
|
xor bx,bx ; start with handle zero
|
|
f5D01_10:
|
|
mov ah,MS_X_COMMIT
|
|
call dos_entry ; commit this file
|
|
inc bx ; onto next candidate
|
|
cmp bx,0FFh ; runout yet ?
|
|
jb f5D01_10 ;
|
|
ret
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 5D02 ***
|
|
; *** Close file by name ***
|
|
; *****************************
|
|
;
|
|
f5D02:
|
|
;-----
|
|
; Close file by name. We do a search first to find out about the file.
|
|
; As long as it's local we call share with the directory cluster/index
|
|
; to close it if it's open.
|
|
;
|
|
mov di,dx ; ES:DI -> register block
|
|
mov dx,RDC_DX
|
|
mov es,RDC_DS ; ES:DX -> filename to close
|
|
push dma_offset
|
|
push dma_segment
|
|
mov dma_offset,offset fcb_search_buf
|
|
mov dma_segment,ds
|
|
mov cx,DA_RO+DA_SYSTEM+DA_HIDDEN
|
|
mov ah,MS_X_FIRST ; look for this file
|
|
call dos_entry ; to get dir entry info
|
|
pop dma_segment
|
|
pop dma_offset
|
|
jc f5Dret
|
|
mov al,fcb_search_buf ; get drive #
|
|
test al,al ; reject networked drives
|
|
js f5Dret
|
|
dec ax ; make drive zero based
|
|
mov cx,word ptr fcb_search_buf+0Dh
|
|
; CX = directory count
|
|
mov dx,word ptr fcb_search_buf+0Eh
|
|
; DX = parent directory cluster
|
|
lea bx,fcb_search_buf+1 ; DS:BX -> name
|
|
mov di,S_CLOSE_IF_OPEN
|
|
; jmps f5D_common
|
|
f5D_common:
|
|
callf lock_tables ; protect SHARE with a critical section
|
|
callf share_stub[di]
|
|
callf unlock_tables ; safe again
|
|
f5Dret:
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 5D03 ***
|
|
; *** Close files by machine***
|
|
; *****************************
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 5D04 ***
|
|
; *** Close by Machine/PSP ***
|
|
; *****************************
|
|
f5D03:
|
|
f5D04:
|
|
;-----
|
|
; Close all files for given PSP
|
|
;
|
|
mov di,S_CLOSE_FILES
|
|
jmps f5D_common
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 5D05 ***
|
|
; *****************************
|
|
;
|
|
f5D05:
|
|
; On Entry:
|
|
; RDC.BX = Share File # to look to
|
|
; RDC.CX = Share Record # to look for
|
|
; On Exit:
|
|
; AX = DOSHNDL Attribute Word
|
|
; BX = machine ID
|
|
; CX = locked blocks count
|
|
; ES:DI -> buffer containing full pathname
|
|
;
|
|
;
|
|
callf lock_tables ; protect SHARE with a critical section
|
|
callf share_stub+S_GET_LIST_ENTRY
|
|
callf unlock_tables ; safe again
|
|
jnc f5Dret ; just return if it went OK
|
|
jmp error_ret ; else return error code in AX
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 5D06 ***
|
|
; *** Get Internal Data ***
|
|
; *****************************
|
|
;
|
|
f5D06:
|
|
mov cx,offset swap_indos ; Calculate Size of Swap
|
|
sub cx,offset internal_data ; Swap INDOS Array
|
|
call return_CX ; CX = Swap Indos length
|
|
mov dx,offset swap_always ; Calculate Size of Swap
|
|
sub dx,offset internal_data ; Swap ALWAYS Array
|
|
call return_DX ; DX = Swap Always length
|
|
mov si,offset internal_data
|
|
call return_DSSI
|
|
mov ax,5D06h
|
|
jmp return_AX_CLC
|
|
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 5D0A ***
|
|
; ***Set Extended Error Info***
|
|
; *****************************
|
|
;
|
|
f5D0A:
|
|
mov si,dx ; ES:SI -> parameter block
|
|
lods es:word ptr [si]
|
|
mov error_code,ax ; copy the appropriate fields
|
|
lods es:word ptr [si]
|
|
mov error_class,ah
|
|
mov error_action,al
|
|
lods es:word ptr [si]
|
|
mov error_locus,ah
|
|
add si,2*WORD ; skip to device
|
|
lods es:word ptr [si]
|
|
mov error_dev,ax
|
|
lods es:word ptr [si]
|
|
mov error_dev+2,ax
|
|
xor ax,ax ; return AL=0
|
|
ret
|
|
;
|
|
; *****************************
|
|
; *** Get switch character ***
|
|
; *****************************
|
|
;
|
|
;
|
|
Public func37
|
|
func37:
|
|
cmp al,1 ! jb f37_getswitch ; Get the current Switch Character
|
|
je f37_setswitch ; Set the Switch Character
|
|
cmp al,3 ! je f37_s03 ; Sub-Func 03 Return Unchanged
|
|
mov dl,0ffh ! jb f37_return_DX ; Sub-Func 02 Return DL == 0FFh
|
|
mov al,0FFh ; else invalid sub-function
|
|
f37_s03:
|
|
ret
|
|
|
|
f37_getswitch:
|
|
mov dl,switch_char
|
|
f37_return_DX:
|
|
jmp return_DX ; return current setting in DX
|
|
|
|
f37_setswitch:
|
|
mov switch_char,dl
|
|
ret
|
|
|
|
;**************************************************
|
|
;**************************************************
|
|
;*** ***
|
|
;*** Miscellaneous Isolated Functions ***
|
|
;*** ***
|
|
;**************************************************
|
|
;**************************************************
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 30 ***
|
|
; *** Get Version Number ***
|
|
; *****************************
|
|
|
|
Public func30
|
|
func30:
|
|
if DOS5
|
|
mov es,current_psp ; version is kept in the PSP
|
|
mov ax,PSP_VERSION
|
|
else
|
|
mov ax,dos_version ; version returned in AX
|
|
endif
|
|
ReturnVersionNumber:
|
|
xor bx,bx ; zero BX and CX
|
|
xor cx,cx
|
|
call return_BX
|
|
call return_CX
|
|
jmp return_AX_CLC
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 33 ***
|
|
; *** Get/Set Cntl-Break ***
|
|
; *****************************
|
|
Public func33
|
|
|
|
; WARNING - called on USER stack
|
|
|
|
func33:
|
|
cmp al,2 ; range check subfunction
|
|
jbe f33_10
|
|
mov dl,bootDrv ; assume we want boot drive
|
|
cmp al,5 ; did we ?
|
|
je f33_30
|
|
if DOS5
|
|
cmp al,6 ; get true version ?
|
|
je f33_60
|
|
endif
|
|
mov reg_AL[bp],0FFh ; return AL = FF
|
|
ret ; Illegal function request
|
|
f33_10:
|
|
and dl,01h ; force a valid value
|
|
cmp al,1 ; check for get or set
|
|
jae f33_20
|
|
mov dl,break_flag ; it's a get, so use existing setting
|
|
f33_20:
|
|
xchg dl,break_flag ; replace current setting
|
|
je f33_40
|
|
f33_30:
|
|
mov reg_DL[bp],dl ; return setting in DL
|
|
f33_40:
|
|
ret
|
|
|
|
if DOS5
|
|
f33_60:
|
|
mov reg_BX[bp],TRUE_VERSION ; return version number
|
|
mov ax,patch_version
|
|
mov reg_DX[bp],ax ; return revision+HMA
|
|
ret
|
|
endif
|
|
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 25 ***
|
|
; *** Set Interrupt Vector ***
|
|
; *****************************
|
|
;
|
|
|
|
; WARNING - use no stack as device drivers have called us re-entrantly
|
|
|
|
Public func25
|
|
func25:
|
|
mov bx,es ; is really dos_DS - save for later
|
|
xor di,di ; replace with the values in dos_DS:DX
|
|
mov es,di ; es -> zero segment
|
|
xor ah,ah ; the interrupt number
|
|
mov di,ax ; 0:di -> vector
|
|
shl di,1 ! shl di,1 ; 4 bytes per vector
|
|
|
|
cli
|
|
xchg ax,dx ; Get New Offset
|
|
stosw ; and Save
|
|
xchg ax,bx ; Get New Segment
|
|
stosw ; and Save
|
|
sti
|
|
xchg ax,dx ; recover entry AL to (preserve it)
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 35 ***
|
|
; *** Get Interrupt Vector ***
|
|
; *****************************
|
|
|
|
; WARNING - use no stack as device drivers have called us re-entrantly
|
|
|
|
Public func35
|
|
func35:
|
|
xor bx,bx
|
|
mov ds,bx ; DS:0 -> vector table
|
|
mov bl,al ; BX = the interrupt number
|
|
shl bx,1 ! shl bx,1 ; 4 bytes per vector
|
|
lds bx,ds:dword ptr [bx] ; DS:BX -> vector
|
|
les di,ss:int21regs_ptr
|
|
mov es:reg_BX[di],bx
|
|
mov es:reg_ES[di],ds
|
|
jmp get_dseg ; restore DS for return
|
|
|
|
;PC-DOS Verify and Break Flags Support
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 2E ***
|
|
; *** Set/Reset Verify ***
|
|
; *****************************
|
|
Public func2E
|
|
func2E:
|
|
and al,1 ; only use bottom bit
|
|
mov verify_flag,al ; store for use later
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 54 ***
|
|
; *** Get Verify Setting ***
|
|
; *****************************
|
|
Public func54
|
|
func54:
|
|
mov al,verify_flag ; return verify flag
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 63 ***
|
|
; *** Get Lead Byte Table ***
|
|
; *****************************
|
|
;
|
|
|
|
|
|
Public func63
|
|
func63:
|
|
cmp al, 1 ; subfunction #?
|
|
jb f63_get_tbl ; subfunction 0
|
|
je f63_set_flg ; subfunction 1
|
|
cmp al, 2 ; subfunction 2?
|
|
je f63_get_flg ; yes
|
|
|
|
mov ax, ED_FUNCTION ; invalid subfunction number
|
|
jmp error_exit ; so quit
|
|
|
|
|
|
f63_get_flg:
|
|
; Get the current state of the DOS interim character console flag.
|
|
; If this flag is set int 21h functions 07h, 08h, 0Bh, 0Ch are supposed
|
|
; to return "interim character information" which I assume is incomplete
|
|
; characters. (In languages like Korean a given double byte character
|
|
; may be built by the user entering several keystrokes which form
|
|
; incomplete characters.)
|
|
mov es, current_psp
|
|
mov dl, PSP_RIC ; Return Interim Character flag
|
|
jmp return_DX ; flag returned in dl
|
|
|
|
|
|
f63_set_flg:
|
|
; Set the current state of the DOS interim character console flag.
|
|
; dos_DL = 0 - clear flag, dos_DL = 1 - set flag
|
|
mov es, current_psp
|
|
mov PSP_RIC, dl ; record flag
|
|
ret
|
|
|
|
|
|
f63_get_tbl:
|
|
; Get the current DBCS table address.
|
|
mov si,offset DBCS_tbl+2; skip the table size entry
|
|
; jmp return_DSSI
|
|
|
|
return_DSSI:
|
|
;-----------
|
|
; On Entry:
|
|
; DS:SI to be returned to caller
|
|
; On Exit:
|
|
; AX preserved
|
|
;
|
|
les di,ss:int21regs_ptr
|
|
mov es:reg_DS[di],ds
|
|
mov es:reg_SI[di],si
|
|
ret
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 29 ***
|
|
; *** Parse String ***
|
|
; *****************************
|
|
Public func29
|
|
func29:
|
|
;
|
|
; Entry:
|
|
; DS:SI -> line to parse
|
|
; ES:DI -> resulting fcb
|
|
; Exit:
|
|
; DS:SI -> terminating delimeter past parsed filename
|
|
; ES:DI -> filled in fcb (Affects 16 bytes: DnnnnnnnnTTT0000)
|
|
;
|
|
push ds
|
|
push es
|
|
call reload_ES
|
|
pop ds
|
|
call parse
|
|
call return_DSSI ; return result of parse
|
|
pop ds
|
|
mov al,dh ; return result in AL
|
|
ret
|
|
|
|
;-----
|
|
parse: ; parse DOS filename delimited by TAB,SPACE,or .,+:;=|"/\[]<> or ctrl
|
|
;-----
|
|
; Entry:
|
|
; DS:SI -> line to parse
|
|
; ES:DI -> fcb to parse into
|
|
; AL == bit options:
|
|
; Bit 0 == 1: scan off leading delimiters
|
|
; Bit 1 == 1: change drive only if specified
|
|
; Bit 2 == 1: change name " " "
|
|
; Bit 3 == 1: change type " " "
|
|
; Exit:
|
|
; DS:SI -> terminating delimeter past parsed filename
|
|
; ES:DI -> filled in fcb (Affects 16 bytes: DnnnnnnnnTTT0000)
|
|
; DH == 1 if wild, 0FFh if the drive is invalid, 0 otherwise
|
|
;
|
|
push di ; (<--keep DI last on stack)
|
|
|
|
cld ; ChSh
|
|
xor dx,dx ; DH = default return value (0)
|
|
xchg al,dl ; put flags into DL, AL = 0
|
|
|
|
mov cx,1
|
|
test dl,0010b ; should we initialize drive?
|
|
call nz_store_al ; do conditional store
|
|
|
|
mov al,' ' ; use spaces for filename & typ
|
|
|
|
mov cl,8
|
|
test dl,0100b ; should we initialize the name?
|
|
call nz_store_al
|
|
|
|
mov cl,3
|
|
test dl,1000b ; should we initialize the typ?
|
|
call nz_store_al
|
|
|
|
xor ax,ax ; zero-out the 4 post-typ bytes
|
|
stos ax
|
|
stos ax
|
|
|
|
pop di ! push di ; restore DI to start of FCB
|
|
|
|
deblank_loop:
|
|
lods al ; grab char
|
|
cmp al,' ' ; is it a blank?
|
|
je deblank_loop ; Y: keep looping
|
|
cmp al,'I'-'@' ; is it a tab?
|
|
je deblank_loop ; Y: keep looping
|
|
|
|
test dl,0001b ; skip-delimiter-bit set?
|
|
jz parse_drive ; N: go start parsing
|
|
|
|
skip_delim_loop:
|
|
call check_delimiters ; check AL for delimiterness
|
|
jb parse_dec_ret ; found terminator, dec SI & leave
|
|
mov dl,dh ; flag no-more-delimiter-skip (DL = 0)
|
|
je deblank_loop ; found separator, go deblank after it
|
|
|
|
parse_drive:
|
|
dec si
|
|
cmp byte ptr 1[si],':' ; is the drive specified?
|
|
jne parse_name
|
|
lods ax ; get drive, junk colon
|
|
and al,01011111b ; upper case it
|
|
sub al,'@' ; AL = 1-relative drive #
|
|
push ax ! push ds ; Save the drive code and call
|
|
call get_dseg ; Restore our Data Segment
|
|
call valid_drive ; routine to validate drive ZR == OK
|
|
pop ds ! pop ax ; Restore drive code and User DS
|
|
jz parse_d10
|
|
dec dh ; flag drive error (0FFh)
|
|
parse_d10:
|
|
mov es:[di],al ; insert drive in fcb
|
|
|
|
parse_name:
|
|
inc di ; DI -> fname
|
|
mov cx,8
|
|
call parse_item ; parse an up-to 8 char filename
|
|
cmp dl,'.' ; was the delimeter a '.'?
|
|
jne parse_dec_ret ; N: the parse is complete
|
|
|
|
mov cl,3
|
|
call parse_item ; parse an up-to 3 char filetype
|
|
parse_dec_ret:
|
|
dec si ; bump SI back to point to delimeter
|
|
|
|
parse_ret:
|
|
pop di
|
|
ret
|
|
|
|
|
|
;-----------
|
|
nz_store_al:
|
|
;-----------
|
|
; Entry:
|
|
; DI -> destination to conditionally initialize
|
|
; CX == length of destination
|
|
; AL == byte to initialize with
|
|
; ZF set: do not initialize destination
|
|
; Exit:
|
|
; DI -> past destination (initial DI+CX)
|
|
; Changed:
|
|
; CX,DI
|
|
;
|
|
jnz skip_store ; should we initialize?
|
|
rep stosb ; Y: store them bytes
|
|
skip_store:
|
|
add di,cx ; bump DI to post-dest position
|
|
ret
|
|
|
|
|
|
;==========
|
|
parse_item: ; Parses item into fcb if item is specified
|
|
;==========
|
|
;
|
|
; Entry:
|
|
; SI -> item to parse (name or type)
|
|
; DI -> fcb area to parse it into
|
|
; CX == length of item
|
|
; DH == parse_return
|
|
; Exit:
|
|
; SI -> past ending delimeter
|
|
; DI -> past fcb area (initial DI + CX)
|
|
; CH == If zero on enter zero on exit else 0-255
|
|
; DH == updated parse_return w/possible wild bit set
|
|
; DL == character delimiter @(SI-1)
|
|
; Changed:
|
|
; AX,CX,DX,SI,DI
|
|
;
|
|
|
|
mov ah,FALSE ; specified item flag
|
|
parse_item_loop:
|
|
lods al ; get char
|
|
call check_delimiters ; is it a delimiter?
|
|
jbe pi_pad_ret ; Y: the parse is complete
|
|
jcxz parse_item_loop ; if the name is full, skip the char
|
|
mov ah,al ; flag name as present
|
|
cmp al,'?' ; is it a single wild char?
|
|
je pi_set_wild ; Y: set wild flag
|
|
cmp al,'*' ; is it a multi-char wild card?
|
|
jne pi_store ; N: store it
|
|
mov al,'?' ; Y: fill with '?' to end of name
|
|
rep stosb
|
|
pi_set_wild:
|
|
or dh,1 ; set wild flag
|
|
jcxz parse_item_loop ; skip store if name is now filled
|
|
pi_store:
|
|
dec cx ; another char done
|
|
call dbcs_lead ; is it the 1st byte of kanji ?
|
|
jne pi_store10
|
|
inc si ; skip 2nd byte
|
|
jcxz parse_item_loop ; can I copy both ?
|
|
dec cx ; yes, do so
|
|
stosb
|
|
dec si ; point at second byte
|
|
lodsb ; so we can copy it too..
|
|
pi_store10:
|
|
stos al ; put the char in the fcb
|
|
jmps parse_item_loop
|
|
pi_pad_ret:
|
|
mov dl,al ; DL = ending delimeter
|
|
or ah,ah ; the the item specified?
|
|
jz pi_ret ; N: skip padding
|
|
mov al,' ' ; Y: pad to end with spaces
|
|
rep stosb
|
|
pi_ret:
|
|
add di,cx ; bump DI out to end
|
|
ret
|
|
|
|
|
|
;----------------
|
|
check_delimiters:
|
|
;----------------
|
|
;
|
|
; Entry:
|
|
; AL == char to check in list of delimiters
|
|
; Exit:
|
|
; AL == char changed to uppercase
|
|
; CF set if it is one of the terminators: |"/\[]<> & ctrl chars != TAB
|
|
; ZF set if it is one of the separators: .,+:;= SPACE & TAB
|
|
; OR one of the non-ctrl terminators
|
|
;
|
|
|
|
cmp al,'a' ; check for lower case
|
|
jb not_lower
|
|
cmp al,'z'
|
|
ja not_lower
|
|
and al,01011111b ; uppercase it, CF clear, ZF clear
|
|
ret
|
|
not_lower:
|
|
push cx ! push di ! push es
|
|
push cs ! pop es ; ES = Code segment
|
|
mov di,offset parse_separators
|
|
mov cx,length parse_separators
|
|
repne scasb ; is AL a separator?
|
|
je cpd_pop_ret ; Y: return ZF set
|
|
mov cl,length parse_terminators
|
|
repne scasb ; is AL a terminator?
|
|
stc ; (set CF if true)
|
|
je cpd_pop_ret ; Y: return CF & ZF set
|
|
cmp al,' ' ; (AL == ' ') ZF set, (AL < ' ') CF set
|
|
cpd_pop_ret:
|
|
pop es ! pop di ! pop cx
|
|
ret
|
|
|
|
;
|
|
; *****************************
|
|
; *** DOS Function 2A ***
|
|
; *** Get Current Date ***
|
|
; *****************************
|
|
Public func2A
|
|
func2A:
|
|
;
|
|
; entry: None
|
|
;
|
|
; exit: cx = year (1980-2099)
|
|
; dh = month (1-12)
|
|
; dl = day (1-31)
|
|
; al = DOS returns day of week here
|
|
;
|
|
call ReadTimeAndDate ; Get the current Time and Date
|
|
mov cx,1980
|
|
add cx,yearsSince1980
|
|
; mov dl,dayOfMonth
|
|
; mov ah,month
|
|
mov dx,word ptr dayOfMonth
|
|
mov al,dayOfWeek
|
|
jmps f2C_10 ; exit via common routine
|
|
|
|
; *****************************
|
|
; *** DOS Function 2C ***
|
|
; *** Get Current Time ***
|
|
; *****************************
|
|
Public func2C
|
|
func2C:
|
|
;
|
|
; entry: None
|
|
;
|
|
; exit: ch = hours (0-23)
|
|
; cl = minutes (0-59)
|
|
; dh = seconds (0-59)
|
|
; dl = Hunredths seconds (0-99)
|
|
; al = 0
|
|
;
|
|
call ReadTimeAndDate ; Get the current Time and Date
|
|
mov cx,biosDate+2 ; Get the Hour and Minute
|
|
mov dx,biosDate+4 ; Get the Seconds and Hundredths
|
|
xor ax,ax ; return AL = 0
|
|
f2C_10:
|
|
call return_CX ; and return to caller
|
|
jmp return_DX
|
|
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 2B ***
|
|
; *** Set Current Date ***
|
|
; *****************************
|
|
Public func2B
|
|
func2B:
|
|
;
|
|
; entry: cx = year (1980-2099)
|
|
; dh = month (1-12)
|
|
; dl = day (1-31)
|
|
;
|
|
; exit: al = 00H success
|
|
; = FFH failure
|
|
;
|
|
call ConvertDate ; Convert to BIOS date
|
|
jc f2B_20 ; Abort on Error
|
|
push cx ; save the converted date
|
|
call ReadTimeAndDate ; Get the current Time and Date
|
|
pop biosDate ; new date, existing time
|
|
f2B_10: ; Set the current Time and Date
|
|
call rw_clock_common ; make sure clock is there/setup regs
|
|
call device_write ; Update the Date and Time
|
|
xor ax,ax
|
|
ret
|
|
|
|
f2B_20:
|
|
mov al,0FFh ; return FAILURE
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 2D ***
|
|
; *** Set Current Time ***
|
|
; *****************************
|
|
Public func2D
|
|
func2D:
|
|
;
|
|
; entry: ch = hours (0-23)
|
|
; cl = minutes (0-59)
|
|
; dh = seconds (0-59)
|
|
; dl = hundredth seconds (0-99)
|
|
;
|
|
; exit: al = 00H success
|
|
; = FFH failure
|
|
;
|
|
cmp ch,23 ; Range check hours
|
|
ja f2B_20
|
|
cmp cl,59 ; Range check minutes
|
|
ja f2B_20
|
|
cmp dh,59 ; Range check seconds
|
|
ja f2B_20
|
|
cmp dl,99 ; Range check hundredths
|
|
ja f2B_20
|
|
push cx ; save hours/mins
|
|
push dx ; save secs/hundredths
|
|
call ReadTimeAndDate ; Get the current Time and Date
|
|
pop biosDate+4 ; leave the date alone
|
|
pop biosDate+2 ; but update the time
|
|
jmps f2B_10 ; Update the Date and Time
|
|
|
|
|
|
Public ReadTimeAndDate
|
|
|
|
ReadTimeAndDate: ; Get the current Time and Date
|
|
call rw_clock_common ; make sure clock is there/setup regs
|
|
call device_read ; read the Date and Time
|
|
mov ax,biosDate ; get the BIOS date and convert
|
|
cmp ax,daysSince1980 ; (but only if necessary)
|
|
jne NewDate
|
|
ret
|
|
|
|
NewDate:
|
|
mov daysSince1980,ax ; so we won't have to convert next time
|
|
inc ax ; Day number starting 1 Jan 1980
|
|
mov cx,ax ; save day count
|
|
inc ax ; convert to a sunday as 1/1/80 is tues
|
|
xor dx,dx
|
|
mov bx,7
|
|
div bx
|
|
mov dayOfWeek,dl ; save day of week
|
|
|
|
xor dx,dx
|
|
mov ax,cx ; recover day count
|
|
|
|
xor di,di ; assume zero leap days
|
|
sub ax,60 ; less than 60 days
|
|
jc no_leap_days ; means no leap days to subtract
|
|
mov bx,1461 ; 1461 = days in four years
|
|
div bx ; get number of leap years since 1980
|
|
inc ax ; include 1980
|
|
sub cx,ax ; normalize years to 365 days
|
|
mov di,ax ; save proper leap day count
|
|
no_leap_days:
|
|
|
|
xor dx,dx
|
|
xchg ax,cx ; DX:AX = years since 1980 * 365
|
|
mov bx,365
|
|
div bx ; get number of years since 1980
|
|
or dx,dx ; check for zero days left
|
|
jnz days_left
|
|
dec ax ; dec year count
|
|
mov dx,365 ; set day count to last day of last year
|
|
days_left:
|
|
|
|
mov yearsSince1980,ax ; save the year
|
|
xchg ax,si ; save in SI
|
|
|
|
xor bx,bx
|
|
mov cx,12
|
|
get_month: ; find the appropriate month
|
|
cmp dx,totaldays[bx]
|
|
jbe got_month
|
|
inc bx ! inc bx
|
|
loop get_month
|
|
got_month:
|
|
shr bx,1 ; BX = month
|
|
mov month,bl
|
|
|
|
dec bx
|
|
shl bx,1 ; BX = index to previous months
|
|
sub dx,totaldays[bx] ; get days into this month
|
|
|
|
cmp bx,2 ; if it's FEB 29th we've lost a day
|
|
jne not_leap_yr ; check it's FEB
|
|
test si,3
|
|
jnz not_leap_yr ; but is it a leap year ?
|
|
shr si,1 ! shr si,1 ; divide years by 4
|
|
inc si ; include this year
|
|
cmp si,di ; compare against leap day adjustment
|
|
jne not_leap_yr
|
|
inc dx ; put 29th feb back again
|
|
not_leap_yr:
|
|
mov dayOfMonth,dl ; save the day of the month
|
|
ret
|
|
|
|
|
|
ConvertDate:
|
|
sub cx,1980 ; Base year is 1980
|
|
jc xset_date_error
|
|
cmp cx,2100-1980 ; Year in valid range ?
|
|
jnc xset_date_error
|
|
mov bl,dh ; Month to BL
|
|
xor bh,bh
|
|
dec bx ; Adjust month to 0-11
|
|
cmp bl,12 ; Month in valid range ?
|
|
jnc xset_date_error
|
|
mov al,dl ; Day of month
|
|
cbw
|
|
test cl,3 ; Leap year ?
|
|
jnz not_leap_year ; Jump if not
|
|
cmp dh,3 ; After February ?
|
|
cmc
|
|
adc al,ah ; Increment days in current year if so
|
|
cmp dl,29 ; Day of month 29 ?
|
|
jz day_valid ; Valid if so
|
|
|
|
not_leap_year:
|
|
dec dx
|
|
cmp dl,monthdays[bx] ; Day of month within range for non-leap
|
|
; year ?
|
|
jnc xset_date_error
|
|
|
|
day_valid:
|
|
shl bx,1
|
|
add ax,totaldays[bx] ; Get total days in current year
|
|
|
|
push ax
|
|
|
|
mov ax,365
|
|
mul cx ; Convert year to days since 1-1-1980
|
|
mov cx,ax
|
|
|
|
; if total (ax) >= 60 (Feb 29 1980) then
|
|
; leap$days = (total - 60) / (365 * 4) + 1
|
|
|
|
sub ax,60 ; Before first leap year date
|
|
jc noleap ; Jump if so
|
|
mov bx,365*4 ; 4 years worth of days (365 * 4)
|
|
sub dx,dx
|
|
div bx ; Get number of leap years - 1
|
|
inc ax
|
|
add cx,ax ; CX now has total days including leap
|
|
; days
|
|
|
|
noleap:
|
|
dec cx
|
|
|
|
pop ax
|
|
|
|
add cx,ax ; Get total days since 1-1-1980
|
|
clc
|
|
ret
|
|
|
|
xset_date_error:
|
|
stc
|
|
ret
|
|
|
|
rw_clock_common:
|
|
mov cx,6 ; read/write 6 characters
|
|
mov dx,offset biosDate ; DX -> 6 byte buffer
|
|
les si,clk_device ; Get the address of the Clock Device
|
|
cmp si,-1 ; Has a valid device been selected
|
|
jne rw_clock_common10
|
|
add sp,WORD ; discard near return address
|
|
rw_clock_common10:
|
|
ret
|
|
|
|
|
|
; *****************************
|
|
; *** DOS Function 38 ***
|
|
; *** Get/Set Country Data ***
|
|
; *****************************
|
|
Public func38
|
|
func38:
|
|
xor ah,ah ; Generate 16 Bit country
|
|
cmp al,0FFh ; FF means country code in BX
|
|
jne f38_10
|
|
xchg ax,bx ; AX = real country code
|
|
f38_10:
|
|
xchg ax,dx ; DX = country
|
|
test dx,dx ; dos_AL = 0 get the current country
|
|
jz f38_get
|
|
inc ax ; now check for dos_DX = FFFF
|
|
jz f38_set ; which means set country code
|
|
dec ax ; no, return buffer to normal
|
|
f38_get:
|
|
test dx,dx ; Get current?
|
|
jnz f38_g10 ; Yes
|
|
mov dx,cur_country ; use current country
|
|
f38_g10:
|
|
; look for (and if neccessary load) type 1 info into buffer
|
|
xchg ax,di ; ES:DI -> buffer
|
|
mov bx,cur_cp ; bx=codepage
|
|
call f38_get_info ; get info in current codepage
|
|
jnc f38_g20
|
|
push ss ! pop ds
|
|
xor bx,bx ; now try any codepage
|
|
call f38_get_info ; if none for current codepage
|
|
jc f38_error ; No Match Found
|
|
f38_g20:
|
|
lea si,EXCI_CI_DATAOFF[si] ; point at CI_, not EXCI_ data
|
|
mov bx,CI_CODE[si] ; Return the selected country code
|
|
mov cx,CI_STATICLEN/2
|
|
rep movsw
|
|
|
|
if NLSFUNC
|
|
push ss
|
|
pop ds
|
|
; call get_dseg ; DS back to PCMODE
|
|
endif
|
|
call return_BX ; return country code in BX
|
|
xchg ax,bx
|
|
jmp return_AX_CLC ; and in AX
|
|
|
|
f38_get_info:
|
|
push es ! push di ! push dx ; save pointer to buffer
|
|
mov al,1 ; Get data list seperators etc...
|
|
call f65_get_info ; DS:SI -> extended country info buffer
|
|
pop dx ! pop di ! pop es ; ES:DI -> users buffer
|
|
ret
|
|
|
|
f38_set:
|
|
mov bx,cur_cp ; bx=codepage
|
|
and bx,f38_flag ; force CP to zero if 1st time here
|
|
call f38_set_country ; Update the Internal Data Structures
|
|
jc f38_error
|
|
f38_s20:
|
|
mov f38_flag,0FFFFh ; Country Code Set Successfully
|
|
mov ax,cur_country ; and return the current country
|
|
jmp return_AX_CLC ; to the user
|
|
|
|
|
|
f38_error:
|
|
|
|
if NLSFUNC
|
|
push ss
|
|
pop ds
|
|
; call get_dseg ; DS back to PCMODE
|
|
endif
|
|
mov ax,ED_FILE ; This is the Error to return
|
|
jmp error_exit
|
|
|
|
|
|
f38_set_country:
|
|
; On Entry:
|
|
; BX = codepage
|
|
; DX = country
|
|
; On Exit:
|
|
; AX = error code
|
|
; preserve codepage/country info if there is an error (ie do type 1 last!)
|
|
;
|
|
mov al,2 ; Get uppercase & filename table
|
|
mov di,offset Ucasetbl
|
|
mov cx,info2_len
|
|
call f38_update
|
|
jc f38_seterr
|
|
mov al,4 ; Get uppercase & filename table
|
|
mov di,offset FileUcasetbl
|
|
mov cx,info4_len
|
|
call f38_update
|
|
jc f38_seterr
|
|
mov al,5 ; Get Legal file characters
|
|
mov di,offset FileCharstbl
|
|
mov cx,info5_len
|
|
call f38_update
|
|
jc f38_seterr
|
|
mov al,6 ; Get Collating table
|
|
mov di,offset Collatingtbl
|
|
mov cx,info6_len
|
|
call f38_update
|
|
jc f38_seterr
|
|
mov al,7 ; Get double byte character set table
|
|
mov di,offset DBCS_tbl
|
|
mov cx,info7_len
|
|
call f38_update
|
|
jc f38_seterr
|
|
mov al,1 ; Get data list seperators etc...
|
|
mov di,offset country_data ; do last since this updates
|
|
mov cx,info1_len ; cur_country/cur_cp
|
|
call f38_update
|
|
; jc f38_seterr
|
|
; clc
|
|
ret
|
|
f38_seterr:
|
|
mov ax,ED_FILE ; return file not found error
|
|
ret
|
|
|
|
f38_update:
|
|
push ds ; save important registers
|
|
push bx ; codepage
|
|
push cx ; count for move
|
|
push dx ; country
|
|
push di ; destination offset for move
|
|
push ds ; destination segment
|
|
call f65_get_info ; DS:SI -> buffer with country info
|
|
pop es ; destination seg in ES
|
|
pop di ; ES:DI -> destination of move
|
|
pop dx ; country
|
|
pop cx ; bytes to move
|
|
pop bx ; codepage back again
|
|
jc f38_update10 ; any problems ?
|
|
rep movsb ; no, copy the data
|
|
f38_update10:
|
|
pop ds ; DS back to PCMDSEG
|
|
ret
|
|
|
|
; *****************************
|
|
; *** DOS Function 65 ***
|
|
; *** Extended Country Data ***
|
|
; *****************************
|
|
;
|
|
;CODEPAGE equ 437 ; Return Standard Code Page
|
|
;
|
|
; Get Extended Country Code Sub-Functions
|
|
;
|
|
func65_dt dw 0FFFFh ; 00 Illegal Sub-Function
|
|
dw offset country_data ; 01 Extended Country Info
|
|
dw offset Ucasetbl ; 02 UpperCase Table
|
|
dw 0FFFFh ; 03 Invalid Subfunction
|
|
dw offset FileUcasetbl ; 04 FileName Upper Case Table
|
|
dw offset FileCharstbl ; 05 Valid Filename Characters
|
|
dw offset Collatingtbl ; 06 Collating Sequence
|
|
dw offset DBCS_tbl ; 07 DBCS Environment Vector
|
|
func65_dtl equ (offset $ - offset func65_dt)/2
|
|
|
|
Public func65
|
|
func65:
|
|
cmp al,func65_dtl ; is sub-function 0-7 ?
|
|
jb func65_read_table
|
|
sub al,20h ; now check for 20-22
|
|
jb f65_invalid
|
|
je func6520 ; it's upper case character
|
|
sub al,2
|
|
je func6522
|
|
jb func6521
|
|
sub al,1 ; how about 6523 ?
|
|
jnz f65_invalid
|
|
; jmp func6523
|
|
|
|
func6523:
|
|
;--------
|
|
; On Entry:
|
|
; DX = character to check
|
|
; On Exit:
|
|
; AX = 0, No
|
|
; AX = 1, Yes
|
|
; AX = 2, neither
|
|
;
|
|
push ds
|
|
pop es
|
|
mov di,offset NoYesChars ; 'NnYy'
|
|
cbw ; assume No (AX=0)
|
|
xchg ax,dx ; AX = char, DX = answer
|
|
call dbcs_lead ; is it 1st of a DBCS pair
|
|
jne func6523_10
|
|
scasw ; check 'N'
|
|
je func6523_30
|
|
inc dx ; assume Yes (DX=1)
|
|
scasw ; check 'Y'
|
|
jmps func6523_20
|
|
func6523_10:
|
|
scasb ; check 'N'
|
|
je func6523_30
|
|
scasb ; check 'n'
|
|
je func6523_30
|
|
inc dx ; assume Yes (DX=1)
|
|
scasb ; check 'Y'
|
|
je func6523_30
|
|
scasb ; check 'y'
|
|
func6523_20:
|
|
je func6523_30
|
|
inc dx ; it's neither (DX=2)
|
|
func6523_30:
|
|
xchg ax,dx ; return result in AX
|
|
jmp return_AX_CLC ; Return the Code Page
|
|
|
|
func6522:
|
|
;--------
|
|
; Upper case ASCIIZ string at ES:DX
|
|
mov cx,0FFFFh ; calculate the length
|
|
mov di,dx ; of the string
|
|
; mov al,0
|
|
repne scasb
|
|
not cx ; CX = length, including 0
|
|
; jmp func6521 ; now use upper case CX bytes
|
|
|
|
func6521:
|
|
;--------
|
|
; Upper case string of CX bytes at ES:DX
|
|
mov si,dx
|
|
mov di,dx ; point SI & DI at string
|
|
f6521_10:
|
|
lods es:al ; read a character
|
|
call dbcs_lead ; is it 1st of a DBCS pair
|
|
jne f6521_20
|
|
stosb ; store 1st byte of this pair
|
|
movs es:byte ptr [di],es:byte ptr [si]
|
|
; copy 2nd byte
|
|
dec cx ; 1st byte of pair
|
|
loopnz f6521_10 ; go around for another one
|
|
ret ; time to go...
|
|
f6521_20:
|
|
call toupper ; upper case the character
|
|
stosb ;
|
|
loop f6521_10 ; go and do another one
|
|
ret
|
|
|
|
func6520:
|
|
;--------
|
|
; Upper case character DL
|
|
xchg ax,dx ; character in AX
|
|
call toupper ; upper case it
|
|
mov dl,al ; return in AL and DL
|
|
jmp return_DX ; set return code
|
|
|
|
f65_invalid:
|
|
;-----------
|
|
; short jump to invalid function
|
|
jmp invalid_function
|
|
|
|
|
|
func65_read_table:
|
|
;-----------------
|
|
cmp cx,5 ; Check for valid buffer size
|
|
jb f65_invalid
|
|
cbw ; Get the request sub-function
|
|
mov si,ax ; into SI
|
|
shl si,1
|
|
mov si,func65_dt[si]
|
|
inc si ; is SI = 0FFFFh
|
|
jz f65_invalid ; if so it's an invalid function
|
|
dec si
|
|
|
|
cmp dx,0ffffh
|
|
jne f65_21 ; FFFF means
|
|
mov dx,cur_country ; use default country
|
|
f65_21:
|
|
cmp bx,0ffffh
|
|
jne f65_22 ; FFFF means
|
|
mov bx,cur_cp ; use default codepage
|
|
f65_22:
|
|
call f65_get_info ; DS:SI -> extended info for this pair
|
|
mov ax,ED_FILE ; On Error return File Not Found
|
|
jnc f65_23 ; for any error
|
|
push ss ! pop ds
|
|
jmp error_exit ; so Quit
|
|
f65_23:
|
|
les bx,ss:int21regs_ptr ; point to callers registers
|
|
mov ax,es:reg_AX[bx] ; get the subfunction number
|
|
mov cx,es:reg_CX[bx] ; this much data is requested
|
|
mov di,es:reg_DI[bx] ; Get the Parameter Block Offset
|
|
mov es,es:reg_ES[bx] ; and Segment
|
|
stosb ; fill in Info ID
|
|
cmp al,1 ; 1 is special - the rest
|
|
jne f65_30 ; want a DWORD ptr
|
|
cmp cx,EXCI_MAXLEN ; Check CX against the sub-function 1
|
|
jbe f65_25 ; maximum and force CX to this value
|
|
mov cx,EXCI_MAXLEN ; if it is greater
|
|
f65_25:
|
|
call return_CX ; Return the number of bytes transfered
|
|
sub cx,EXI_DATA_LEN ; Adjust count for 3 byte header
|
|
mov ax,cx ! stosw ; fill in EXCI_LENGTH
|
|
push cx ; Save the count and copy as much
|
|
cmp cx,EXCI_STATLEN ; valid data a possible. IE at most
|
|
jbe f65_27 ; EXCI_STATLEN bytes
|
|
mov cx,EXCI_STATLEN
|
|
f65_27:
|
|
rep movsb ; just copy the data
|
|
pop cx ; Zero the rest of the data
|
|
sub cx,EXCI_STATLEN ; Skip if no space left in users
|
|
jbe f65_40 ; buffer otherwise STOSB
|
|
xor al,al ! rep stosb
|
|
jmps f65_40
|
|
|
|
;
|
|
; All function 65 sub-functions apart from 01 (Extended Country Info.)
|
|
; pass use this code to update the users parameter block.
|
|
;
|
|
f65_30:
|
|
mov cx,5
|
|
call return_CX
|
|
mov ax,si ! stosw ; fill in the DWORD ptr to the data
|
|
mov ax,ds ! stosw
|
|
f65_40:
|
|
push ss
|
|
pop ds
|
|
; call get_dseg ; back to PCMDSEG
|
|
mov ax,cur_cp ; ##jc## Is the Requested or Current
|
|
jmp return_AX_CLC ; Return the Code Page
|
|
|
|
; *****************************
|
|
; *** DOS Function 66 ***
|
|
; ***Get/Set Global CodePage***
|
|
; *****************************
|
|
;
|
|
Public func66
|
|
func66:
|
|
cbw
|
|
dec ax ! jz f66_10 ; AL = 1, Get the Current CodePage
|
|
dec ax ! jz f66_20 ; AL = 2, Set the Current CodePage
|
|
jmp invalid_function ; Illegal Sub-Function return an Error
|
|
|
|
f66_10: ; Get the Current Code Page Info
|
|
mov bx,cur_cp ; Current CodePage
|
|
call return_BX
|
|
mov dx,SYS_CP ; System CodePage
|
|
jmp return_DX
|
|
|
|
f66_20: ; Set the Current CodePage
|
|
mov dx,cur_country ; The Codepage has changed, so update
|
|
call f38_set_country ; Country Info and tables
|
|
jnc f66_30 ; Reset the Current CodePage if
|
|
mov ax,ED_FILE ; and return the error
|
|
jmp error_exit
|
|
f66_30:
|
|
mov bx,cur_cp ; select the new codepage
|
|
call f66_select_cp ; Prepare CodePage Devices
|
|
jnc f66_40 ; No Errors Skip Error Handler
|
|
mov ax,-65 ; Update Error Status do not generate
|
|
call error_ret ; a critical error but return
|
|
; "access denied" to the application
|
|
f66_40:
|
|
ret
|
|
|
|
|
|
f65_get_info:
|
|
; On Entry:
|
|
; AL = info type
|
|
; BX = codepage (zero means any)
|
|
; DX = country
|
|
; On Exit:
|
|
; CY set if error
|
|
; DS:SI -> buffer with info in it
|
|
;
|
|
; NB. Remember to to Xlat fixups !
|
|
;
|
|
cmp dx,cur_country ; is it default country ?
|
|
jne f65_p30 ; have we already got correct country ?
|
|
test bx,bx ; CP zero special case and we will
|
|
jz f65_p20 ; accept anything for this country
|
|
cmp bx,cur_cp ; otherwise is the codepage
|
|
jne f65_p30 ; in the default system ?
|
|
f65_p20:
|
|
cbw ; make info type a word
|
|
mov si,ax ; into index register
|
|
shl si,1 ; now a word offset
|
|
mov si,func65_dt[si] ; pick up offset of correct table
|
|
jmps f65_p90
|
|
f65_p30:
|
|
push ax
|
|
call f65_locate_and_read ; get info into a buffer at DS:SI
|
|
pop ax
|
|
jc f65_p_exit
|
|
f65_p90:
|
|
cmp al,1 ; was it country info ?
|
|
jne f65_p95 ; no, skip the fixup
|
|
mov CI_CASEOFF+EXCI_CI_DATAOFF[si],offset xlat_xlat
|
|
mov CI_CASESEG+EXCI_CI_DATAOFF[si],ss
|
|
f65_p95:
|
|
clc
|
|
f65_p_exit:
|
|
ret
|
|
|
|
|
|
;
|
|
; **********************************************************************
|
|
; *** Function 65 support - routines for seeking a country/codepage ***
|
|
; *** and loading the required information into the temp data area ***
|
|
; **********************************************************************
|
|
;
|
|
; **************************************************
|
|
; *** Open country.sys and search for the ***
|
|
; *** table of offsets for the given country/ ***
|
|
; *** codepage, read it in and exit. ***
|
|
; **************************************************
|
|
|
|
f65_locate_and_read:
|
|
; Locate and Read info AL for Country DX Codepage BX
|
|
if NLSFUNC
|
|
mov di,offset country_filename
|
|
; point at pathname to country.sys
|
|
xchg ax,cx ; get info into CL
|
|
mov ax,14feh ; then call magic backdoor
|
|
nlsfunc_int2f:
|
|
stc ; assume an error
|
|
int 2fh ; to do the hard work
|
|
ret
|
|
else
|
|
push ax
|
|
call f65x_find_info ; Will need to load up the info
|
|
pop ax
|
|
jc f65_lr_exit ; so do it if we can.
|
|
|
|
mov dx,offset f65xx_temp_area
|
|
mov cx,256 ; read 256 bytes into local buffer
|
|
push ax
|
|
call f65x_load_info ; Load required info
|
|
pop ax
|
|
jc f65_lr_exit
|
|
mov ah,MS_X_CLOSE ; All done so
|
|
mov bx,c_handle ; Close the file first
|
|
call dos_entry ; before leaving
|
|
; jc f65_lr_exit
|
|
mov si,offset f65xx_temp_area ; Tell subroutines where info is
|
|
f65_lr_exit:
|
|
ret
|
|
;
|
|
; Entry: dx=country code, bx=codepage
|
|
; Exit : carry set, and country.sys closed if failure
|
|
; country.sys open ready for more reads if success
|
|
;
|
|
f65x_find_info:
|
|
push es ; Save es
|
|
push ds
|
|
pop es ; Make es=ds
|
|
mov f65xx_country,dx
|
|
mov f65xx_codepage,bx
|
|
mov dx,offset country_filename
|
|
mov ax,(MS_X_OPEN*256)+0 ; Attempt to open country.sys
|
|
test dx,dx
|
|
stc
|
|
jz f65x_40
|
|
call dos_entry ; Handle should come back in ax
|
|
jc f65x_40
|
|
f65x_10:
|
|
mov c_handle,ax ; Save handle
|
|
mov dx,f65xx_country
|
|
cmp f65xx_code,dx ; do we already have the information?
|
|
jne f65x_30 ; No - get it from country.sys
|
|
f65x_20:
|
|
cmp f65xx_cp,bx ; Does codepage agree too?
|
|
je f65x_35 ; Yes so exit with no more ado
|
|
f65x_30:
|
|
mov dx,007Eh
|
|
xor cx,cx ; Seek within country.sys
|
|
mov bx,c_handle
|
|
mov ax,(MS_X_LSEEK*256)+0 ; seek from begining
|
|
call dos_entry
|
|
jc f65x_err
|
|
mov ah,MS_X_READ ; Now read the signature bytes and
|
|
mov bx,c_handle ; check them
|
|
mov cx,2
|
|
mov dx,offset f65xx_sig
|
|
call dos_entry
|
|
jc f65x_err
|
|
cmp f65xx_sig,VALID_SIG
|
|
jne f65x_err ; If signature bad exit
|
|
f65x_32:
|
|
mov ah,MS_X_READ ; Read from country.sys header until
|
|
mov bx,c_handle ; Country/codepage found or NULL
|
|
mov cx,f65xx_ptable_len
|
|
mov dx,offset f65xx_code
|
|
call dos_entry
|
|
jc f65x_err
|
|
cmp f65xx_code,0 ; Found NULL so reqd combination
|
|
je f65x_err ; was not found
|
|
mov dx,f65xx_code ; Get the country/codepage values
|
|
mov bx,f65xx_cp ; read from Country.SYS
|
|
cmp dx,f65xx_country ; Check against the requested
|
|
jne f65x_32 ; Country.
|
|
cmp f65xx_codepage,0 ; If a codepage match is not
|
|
jz f65x_35 ; then return success
|
|
cmp bx,f65xx_codepage ; Check against the requested
|
|
jne f65x_32 ; Codepage
|
|
f65x_35:
|
|
mov f65xx_country,dx ; Force the Search Country and
|
|
mov f65xx_codepage,bx ; CodePage to be Updated
|
|
f65x_40:
|
|
pop es ; combination found so exit
|
|
ret
|
|
|
|
f65x_err:
|
|
pop es
|
|
mov ah,MS_X_CLOSE ; On error close country.sys
|
|
mov bx,c_handle ; and set the carry flag before
|
|
call dos_entry ; leaving
|
|
stc
|
|
ret
|
|
;
|
|
; **************************************************
|
|
; *** Load the type of information requested ***
|
|
; *** For the country currently active in the ***
|
|
; *** offset table ***
|
|
; **************************************************
|
|
;
|
|
; Entry: al=type of info, dx=offset of buffer to read info into cx=no of bytes
|
|
; Exit : carry set, and country.sys closed if failure
|
|
;
|
|
f65x_load_info:
|
|
push es
|
|
push cx
|
|
push dx
|
|
push ds ; Make es=ds
|
|
pop es
|
|
dec al ; 1=Data , 2=uppercase, 4=fuppercase
|
|
sub bh,bh ; 5=filechars, 6=Collating table
|
|
mov bl,al ; 7=DBCS table
|
|
shl bx,1 ; Retrieve relevant offset
|
|
mov dx,f65xx_data[bx]
|
|
xor cx,cx ; Seek within country.sys
|
|
mov bx,c_handle
|
|
mov ax,(MS_X_LSEEK*256)+0 ; seek from begining
|
|
call dos_entry
|
|
pop dx ; Get buffer address back
|
|
pop cx ; and number of bytes to read
|
|
jc f65x_err
|
|
test ax,ax ; zero offset is a problem
|
|
jz f65x_err ; (probably DBCS with old COUNTRY.SYS)
|
|
mov ah,MS_X_READ ; Now read that info into our data area
|
|
mov bx,c_handle
|
|
call dos_entry ; Return when read is done
|
|
jc f65x_err
|
|
pop es
|
|
ret
|
|
endif
|
|
|
|
;
|
|
; This function scans the complete device list and prepares
|
|
; all devices which support codepage.
|
|
;
|
|
; On Entry:
|
|
; BX = codepage
|
|
; On Exit:
|
|
; AX = error code
|
|
|
|
DA_CODEPAGE equ DA_CHARDEV+DA_IOCTL+DA_GETSET
|
|
|
|
f66_select_cp:
|
|
if NLSFUNC
|
|
mov ax,14ffh ; then call magic backdoor
|
|
jmps nlsfunc_int2f ; to do the hard work
|
|
else
|
|
push ds
|
|
mov f66_cp,bx ; Save requested CodePage
|
|
mov preperr,0000 ; Initialize Prepare Error
|
|
push ds ! pop es
|
|
mov bx,offset dev_root ; Get the Root of the Device List
|
|
f66_p10: ; Skip the NUL Device and check
|
|
lds bx,ds:DH_NEXT[bx] ; each character device for CodePage
|
|
cmp bx,0FFFFh ! jz f66_p50 ; Support.
|
|
mov ax,ds:DH_ATTRIB[bx]
|
|
and ax,DA_CODEPAGE ; Check for a Character Device which
|
|
cmp ax,DA_CODEPAGE ; supports IOCTL strings and GETSET
|
|
jne f66_p10 ; otherwise skip the device
|
|
|
|
push bx
|
|
lea si,DH_NAME[bx] ; Found a matching device so
|
|
mov di,offset prepname ; open the device and select the
|
|
mov cx,8 ; requested codepage
|
|
|
|
f66_p20:
|
|
lodsb
|
|
cmp al,' ' ! jz f66_p30
|
|
stosb
|
|
loop f66_p20
|
|
|
|
f66_p30:
|
|
xor al,al ! stosb
|
|
mov ax,(MS_X_OPEN*256)+1 ; Open the device name for
|
|
mov dx,offset prepname ; Write Access
|
|
call dos_entry
|
|
jc f66_perr
|
|
mov bx,ax ; Save Device Handle in BX
|
|
|
|
mov si,es:f66_cp ; Get Requested CodePage in SI
|
|
mov dx,offset cp_packet ; Offset of CodePage Struct
|
|
mov cx,006Ah ; Get Unknown CodePage
|
|
mov ax,(MS_X_IOCTL*256)+0Ch ; Generic IOCTL function
|
|
call dos_entry ; Make function Call
|
|
jc f66_p32 ; Error so Select requested Code Page
|
|
|
|
cmp si,es:cp_cpid ! jz f66_p35 ; If this the currently selected
|
|
f66_p32: ; skip the select CodePage
|
|
mov es:cp_cpid,si
|
|
mov dx,offset cp_packet ; Offset of CodePage Struct
|
|
mov cx,004Ah ; Select Unkown CodePage
|
|
mov ax,(MS_X_IOCTL*256)+0Ch ; Generic IOCTL function
|
|
call dos_entry ; Make function Call
|
|
jnc f66_p35 ; No Error so skip the error
|
|
f66_p33:
|
|
mov es:preperr,ax ; save
|
|
|
|
f66_p35:
|
|
mov ah,MS_X_CLOSE ; Close the device and check
|
|
call dos_entry ; for more devices to be prepared
|
|
jmps f66_p40
|
|
|
|
f66_perr:
|
|
mov es:preperr,ax ; Save the error code and try the
|
|
f66_p40: ; next device in the chain
|
|
pop bx ; Restore the Device offset
|
|
jmps f66_p10 ; and continue
|
|
|
|
f66_p50: ; All device have been prepared
|
|
pop ds ; now return the last error code
|
|
mov ax,preperr ; in AX
|
|
or ax,ax
|
|
ret
|
|
endif
|
|
|
|
PCMODE_DSIZE DSEG PARA
|
|
extrn swap_indos:word
|
|
|
|
PCM_RODATA CSEG WORD
|
|
;
|
|
; Get Internal Data DOS function 5Dh
|
|
;
|
|
func5D_ft dw f5D00
|
|
dw f5D01 ; Commit All
|
|
dw f5D02 ; Close File By Name
|
|
dw f5D03 ; Close All Host Files
|
|
dw f5D04 ; Close Process Host Files
|
|
dw f5D05 ; Get Open File List
|
|
dw f5D06 ; Get DOS Data Area
|
|
dw f5D_msnet ; f5D07 ; Get Truncate Flag used
|
|
; with Redirected Dev I/O
|
|
dw f5D_msnet ; f5D08 ; Set Truncate Flag with
|
|
; with Redirected Dev I/O
|
|
dw f5D_msnet ; f5D09 ; Close All Spool Streams
|
|
dw f5D0A ; Set Extended Error Info
|
|
func5D_ftl equ (offset $ - offset func5D_ft)/2
|
|
dw invalid_function
|
|
|
|
;
|
|
; Data used by the Binary format Time and Date routines
|
|
;
|
|
totaldays dw 0,31,59,90,120,151,181,212,243,273,304,334,0ffffh
|
|
monthdays db 31,28,31,30,31,30,31,31,30,31,30,31
|
|
|
|
parse_separators db TAB,'.,+:;='
|
|
parse_terminators db '|"/\[]<>'
|
|
|
|
|
|
PCMODE_DATA DSEG WORD
|
|
extrn internal_data:word
|
|
extrn error_code:word
|
|
extrn error_class:byte
|
|
extrn error_action:byte
|
|
extrn error_locus:byte
|
|
extrn error_dev:word
|
|
|
|
extrn indos_flag:word
|
|
extrn bootDrv:byte
|
|
extrn current_psp:word
|
|
extrn break_flag:byte
|
|
extrn dma_offset:word
|
|
extrn dma_segment:word
|
|
extrn fcb_search_buf:byte
|
|
extrn func52_data:byte ; Internal Data Table Area
|
|
extrn int21regs_ptr:dword
|
|
extrn lock_tables:dword
|
|
extrn unlock_tables:dword
|
|
extrn share_stub:dword
|
|
extrn remote_call:word ; set to FF if remote machine operation
|
|
extrn swap_always:word
|
|
extrn switch_char:byte
|
|
extrn owning_psp:word
|
|
extrn machine_id:word
|
|
extrn country_data:byte
|
|
extrn cur_country:word
|
|
extrn cur_cp:word
|
|
extrn verify_flag:byte
|
|
|
|
extrn clk_device:dword ; Clock Device Driver Address
|
|
extrn biosDate:word
|
|
extrn daysSince1980:word
|
|
extrn yearsSince1980:word
|
|
extrn month:byte
|
|
extrn dayOfWeek:byte
|
|
extrn dayOfMonth:byte
|
|
extrn hour:byte
|
|
extrn minute:byte
|
|
extrn second:byte
|
|
extrn hundredth:byte
|
|
if DOS5
|
|
extrn WindowsHandleCheck:byte
|
|
else
|
|
extrn win386_remote_machine:dword
|
|
endif
|
|
|
|
SYS_CP equ 437 ; System CodePage
|
|
|
|
|
|
GLOBAL_DATA dseg word
|
|
|
|
f38_flag dw 0 ; Country Code Selected Successfully
|
|
|
|
if not NLSFUNC
|
|
extrn dev_root:dword
|
|
|
|
f66_cp rw 1 ; INT21/66 Local Variable
|
|
cp_packet dw 2 ; Packet Size
|
|
cp_cpid dw 0 ; Request CodePage
|
|
db 0,0 ; Packet Terminators
|
|
|
|
preperr rw 1 ; Prepare function Error Code
|
|
prepname rb 9 ; Reserved for ASCIIZ Device Name
|
|
|
|
;
|
|
; Area for country.sys current pointer table
|
|
; (these are all offsets into country.sys)
|
|
;
|
|
f65xx_code rw 1 ; Country code
|
|
f65xx_cp rw 1 ; Code page
|
|
rw 1 ; +1 reserved
|
|
f65xx_data rw 1 ; Data area
|
|
rw 1 ; Upper case table
|
|
rw 1 ; +1 reserved
|
|
rw 1 ; Filename upper case table
|
|
rw 1 ; Legal file characters
|
|
rw 1 ; Collating table
|
|
rw 1 ; Double byte character set lead byte table
|
|
f65xx_ptable_len equ offset $ - offset f65xx_code
|
|
|
|
f65xx_temp_area rb 256 ; Data area for extended country info
|
|
f65xx_codepage rw 1
|
|
f65xx_country rw 1
|
|
f65xx_sig rw 1 ; Signature
|
|
c_handle rw 1
|
|
|
|
endif ;not NLSFUNC
|
|
|
|
end
|