432 lines
10 KiB
NASM
432 lines
10 KiB
NASM
|
PAGE ,132
|
||
|
TITLE DXFIND.ASM -- Dos Extender Find File Routine
|
||
|
|
||
|
; Copyright (c) Microsoft Corporation 1988-1991. All Rights Reserved.
|
||
|
|
||
|
;***********************************************************************
|
||
|
;
|
||
|
; DXFIND.ASM -- Dos Extender Find File Routine
|
||
|
;
|
||
|
;-----------------------------------------------------------------------
|
||
|
;
|
||
|
; This module provides the locate file logic for the 286 DOS Extender.
|
||
|
;
|
||
|
;-----------------------------------------------------------------------
|
||
|
;
|
||
|
; 09/27/89 jimmat Original version -- considerable code taken from
|
||
|
; old GetChildName routine in dxinit.asm.
|
||
|
;
|
||
|
;***********************************************************************
|
||
|
|
||
|
.286p
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; INCLUDE FILE DEFINITIONS
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
.xlist
|
||
|
.sall
|
||
|
include segdefs.inc
|
||
|
include gendefs.inc
|
||
|
.list
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; GENERAL SYMBOL DEFINITIONS
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; EXTERNAL SYMBOL DEFINITIONS
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
extrn strcpy:NEAR
|
||
|
extrn toupper:NEAR
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; DATA SEGMENT DEFINITIONS
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXDATA segment
|
||
|
|
||
|
extrn segPSP:WORD
|
||
|
extrn rgbXfrBuf1:BYTE
|
||
|
|
||
|
DXDATA ends
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; CODE SEGMENT VARIABLES
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXCODE segment
|
||
|
|
||
|
szPath db 'PATH',0
|
||
|
szWindir db 'WINDIR',0
|
||
|
|
||
|
DXCODE ends
|
||
|
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
subttl Find File Routine
|
||
|
page
|
||
|
; -------------------------------------------------------
|
||
|
; FIND FILE ROUTINE
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXCODE segment
|
||
|
assume cs:DXCODE
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; FindFile -- This routine is used to locate a particular file.
|
||
|
; If successful, this routine will setup the buffer in rgbXfrBuf1
|
||
|
; at offset EXEC_PROGNAME with the string for the file name that
|
||
|
; can be used in a DOS open call.
|
||
|
;
|
||
|
; This routine searches for the file in the following sequence:
|
||
|
;
|
||
|
; 1) If the file name contains a relative or complete path
|
||
|
; component, only look for that particular file,
|
||
|
;
|
||
|
; otherwise:
|
||
|
;
|
||
|
; 1) Look int the environment for a WINDIR= variable, and if
|
||
|
; found, check that directory first.
|
||
|
; 2) Look in the directory the dos extender was loaded from
|
||
|
; 3) Look in the current directory
|
||
|
; 4) Look in all directories in the PATH environment variable
|
||
|
;
|
||
|
; NOTE: This routine must be called in real mode!
|
||
|
;
|
||
|
; Input: RELOC_BUFFER has the file name to search for.
|
||
|
; EXEC_DXNAME has the complete path the dos extender
|
||
|
; Output: EXEC_PROGNAME has complete path to child program.
|
||
|
; Errors: returns CY set if unable to find child
|
||
|
; Uses: All registers preserved
|
||
|
|
||
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
||
|
public FindFile
|
||
|
|
||
|
FindFile proc near
|
||
|
|
||
|
pusha
|
||
|
push ds
|
||
|
push es
|
||
|
|
||
|
push ds
|
||
|
pop es
|
||
|
assume es:DGROUP
|
||
|
|
||
|
; If the base file name contains a ':' '\' or '/', then we'll see if the
|
||
|
; file can be found with that name. This isn't exactly the way Windows wants
|
||
|
; us to search for kernel, but allows a user to specify a relative or complete
|
||
|
; path on the command line. If we get run for Windows/286 pMode, the base
|
||
|
; child name will not include any of these characters, so we will not make
|
||
|
; this check.
|
||
|
|
||
|
mov si,offset RELOC_BUFFER
|
||
|
@@: lodsb
|
||
|
or al,al
|
||
|
jz fndf20 ;no path characters, go do other search
|
||
|
cmp al,':'
|
||
|
jz fndf10
|
||
|
cmp al,'\'
|
||
|
jz fndf10
|
||
|
cmp al,'/'
|
||
|
jnz @b
|
||
|
|
||
|
; The name seems to include a path component. We just want to look for that
|
||
|
; file, and only that file.
|
||
|
|
||
|
fndf10: mov si,offset RELOC_BUFFER
|
||
|
mov di,offset EXEC_PROGNAME
|
||
|
mov dx,di
|
||
|
call strcpy
|
||
|
|
||
|
mov ax,4300h ;use get file attributes to check
|
||
|
int 21h
|
||
|
jmp fndf90 ;found it or not, either way we're done
|
||
|
|
||
|
; The file name doesn't include a path component. If we were run for pMode
|
||
|
; Windows, the environment should include a WINDIR= entry that points to
|
||
|
; the Windows directory. Look for this env variable, and check that directory
|
||
|
; first.
|
||
|
|
||
|
fndf20:
|
||
|
push es ;look for the
|
||
|
push cs ;WINDIR= env variable
|
||
|
pop es
|
||
|
assume es:NOTHING
|
||
|
mov di,offset DXCODE:szWindir
|
||
|
call GetEnv
|
||
|
pop es
|
||
|
assume ds:NOTHING,es:DGROUP
|
||
|
|
||
|
jnz fndf_dosx_dir
|
||
|
|
||
|
; Found WINDIR, copy over the path name, add child name and search
|
||
|
|
||
|
mov di,offset EXEC_PROGNAME ;copy WINDIR path
|
||
|
mov dx,di
|
||
|
call strcpy
|
||
|
|
||
|
cmp byte ptr es:[di-1],'\' ;add trailing \ if necessary
|
||
|
jz @f
|
||
|
mov byte ptr es:[di],'\'
|
||
|
inc di
|
||
|
@@:
|
||
|
push es ;ds back to DGROUP
|
||
|
pop ds
|
||
|
assume ds:DGROUP
|
||
|
|
||
|
mov si,offset RELOC_BUFFER ;add child name
|
||
|
call strcpy
|
||
|
|
||
|
mov ax,4300h ;use get file attributes to check
|
||
|
int 21h
|
||
|
jc fndf_dosx_dir ;no there, go do next check
|
||
|
jmp fndf90 ;found it!
|
||
|
|
||
|
; Next, we try looking in the directory that the Dos Extender was loaded
|
||
|
; from. Start with the complete path to the Dos Extender program file.
|
||
|
|
||
|
fndf_dosx_dir:
|
||
|
|
||
|
push es
|
||
|
pop ds
|
||
|
assume ds:DGROUP
|
||
|
|
||
|
mov si,offset EXEC_DXNAME
|
||
|
mov di,offset EXEC_PROGNAME
|
||
|
mov dx,di
|
||
|
call strcpy
|
||
|
|
||
|
; Now, search backward from the end of the string until we find the
|
||
|
; first backslash or colon. This will take us back past the file name
|
||
|
; and leave us with the raw path.
|
||
|
|
||
|
fndf24: dec di
|
||
|
cmp di,dx ;check if we have gone back past the start
|
||
|
; of the string. (DX still has the address
|
||
|
; of the start of the buffer from above)
|
||
|
jb fndf_cd ;and if so skip this part as the path is null.
|
||
|
mov al,es:[di]
|
||
|
cmp al,':'
|
||
|
jz fndf26
|
||
|
cmp al,'\'
|
||
|
jnz fndf24
|
||
|
|
||
|
; Add the file name string onto the raw path and see if the file exists.
|
||
|
|
||
|
fndf26: inc di
|
||
|
mov si,offset RELOC_BUFFER
|
||
|
call strcpy
|
||
|
|
||
|
mov ax,4300h ;use get file attributes to check
|
||
|
int 21h
|
||
|
jc fndf_cd
|
||
|
jmp fndf90
|
||
|
|
||
|
; We didn't find the file in the same directory as the Extender itself.
|
||
|
; Now, try looking for the file in the current directory!
|
||
|
|
||
|
fndf_cd:
|
||
|
mov di,offset EXEC_PROGNAME ;build current directory path string
|
||
|
dossvc 19h
|
||
|
add al,'A'
|
||
|
stosb ;drive letter
|
||
|
|
||
|
mov ax,'\:'
|
||
|
stosw
|
||
|
|
||
|
xor dl,dl
|
||
|
mov si,di
|
||
|
dossvc 47h ;current directory
|
||
|
|
||
|
mov al,es:[di] ;check if it's the root
|
||
|
or al,al ;empty string?
|
||
|
jz short fndf_cd_cpy ;yes, don't add another '\'
|
||
|
|
||
|
@@: lodsb ;find end of string
|
||
|
or al,al
|
||
|
jnz @b
|
||
|
|
||
|
mov byte ptr [si-1],'\' ;add ending \
|
||
|
|
||
|
fndf_cd_cpy:
|
||
|
mov di,si ;add base child name
|
||
|
mov si,offset RELOC_BUFFER
|
||
|
call strcpy
|
||
|
|
||
|
mov dx,offset EXEC_PROGNAME ;use get file attributes to check
|
||
|
mov ax,4300h
|
||
|
int 21h
|
||
|
|
||
|
jc fndf30
|
||
|
jmp short fndf90
|
||
|
|
||
|
; We didn't find it in the current directory, look at the PATH
|
||
|
; environment variable and see if the file can be found in any of
|
||
|
; its directories. First off, search for the PATH environment
|
||
|
; string.
|
||
|
|
||
|
fndf30:
|
||
|
push es
|
||
|
mov di,offset DXCODE:szPath ;point ES:DI to path str
|
||
|
push cs
|
||
|
pop es
|
||
|
assume es:NOTHING
|
||
|
|
||
|
call GetEnv ;find the path env var
|
||
|
assume ds:NOTHING
|
||
|
|
||
|
pop es
|
||
|
assume es:DGROUP
|
||
|
|
||
|
jnz fndf80 ;Z flag set if FOUND
|
||
|
|
||
|
; We are pointing at the beginning of the path environment variable. We need
|
||
|
; to loop for each directory specified to see if we can find the file in
|
||
|
; that directory.
|
||
|
|
||
|
mov bx,ds ;keep env segment in BX
|
||
|
|
||
|
fndf40: mov ds,bx ;environment segment to DS
|
||
|
assume ds:NOTHING
|
||
|
mov al,ds:[si]
|
||
|
or al,al ;check for end of path variable.
|
||
|
jz fndf80 ;if so, we didn't find any directory with
|
||
|
; the desired file in it.
|
||
|
|
||
|
mov di,offset EXEC_PROGNAME
|
||
|
fndf42: lods byte ptr [si]
|
||
|
cmp al,';' ;is it the separator between strings in
|
||
|
jz fndf52 ; the environment variable?
|
||
|
or al,al ;is it the 0 at the end of the environment
|
||
|
jz fndf50 ; string?
|
||
|
stos byte ptr [di]
|
||
|
jmp fndf42
|
||
|
|
||
|
fndf50: dec si
|
||
|
fndf52: push si ;save pointer to start of next string
|
||
|
mov al,'\'
|
||
|
cmp al,byte ptr es:[di-1] ;dir name already end with \ (root dir?)
|
||
|
jnz fndf54
|
||
|
dec di ; yes, don't make it two \'s
|
||
|
fndf54: stos byte ptr [di]
|
||
|
mov si,offset RELOC_BUFFER ;pointer to file base name
|
||
|
mov ax,es ;put our data segment address in DS
|
||
|
mov ds,ax
|
||
|
assume ds:DGROUP
|
||
|
call strcpy ;append file base name to path
|
||
|
|
||
|
mov ax,4300h ;use get file attributes to check
|
||
|
int 21h
|
||
|
|
||
|
pop si ;restore pointer to start of next string
|
||
|
jc fndf40
|
||
|
jmp short fndf90
|
||
|
|
||
|
; Unable to find the file
|
||
|
|
||
|
fndf80: stc
|
||
|
|
||
|
; Finished, successful or not
|
||
|
|
||
|
fndf90:
|
||
|
pop es
|
||
|
pop ds
|
||
|
popa
|
||
|
ret
|
||
|
|
||
|
FindFile endp
|
||
|
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
; GetEnv -- This routine searches the environment for a
|
||
|
; specific variable.
|
||
|
;
|
||
|
; Input: ES:DI - far pointer to wanted variable name
|
||
|
; Output: DS:SI - far pointer to variable value string
|
||
|
; Errors: return Z true if variable located
|
||
|
; Uses: DS:SI modified, all else preserved
|
||
|
|
||
|
assume ds:DGROUP,es:NOTHING,ss:NOTHING
|
||
|
public GetEnv
|
||
|
|
||
|
GetEnv proc near
|
||
|
|
||
|
push ax
|
||
|
push dx
|
||
|
push di
|
||
|
|
||
|
; Point DS:SI to our environment block
|
||
|
|
||
|
mov ds,segPSP
|
||
|
assume ds:PSPSEG
|
||
|
mov ds,segEnviron
|
||
|
xor si,si
|
||
|
assume ds:NOTHING
|
||
|
|
||
|
; See if DS:SI is pointing at desired environment variable
|
||
|
|
||
|
mov dx,di ;keep var name offset in dx
|
||
|
|
||
|
gete10:
|
||
|
cmp byte ptr es:[di],0 ;at end of variable name?
|
||
|
jz gete50 ; yes, go check '=' & optional blanks
|
||
|
|
||
|
gete20:
|
||
|
lodsb ;get variable char
|
||
|
call toupper ;just in case...
|
||
|
cmp al,es:[di] ;match desired name so far?
|
||
|
jnz gete30 ; no, go find the next var name
|
||
|
|
||
|
inc di ;bump var pointer
|
||
|
jmp short gete10 ; and keep on checking
|
||
|
|
||
|
gete30:
|
||
|
mov di,dx ;reset source name pointer
|
||
|
|
||
|
or al,al ;already at end of this env var?!
|
||
|
jz gete35
|
||
|
|
||
|
@@: lodsb
|
||
|
or al,al ;find next environment var name
|
||
|
jnz @b
|
||
|
gete35:
|
||
|
cmp byte ptr ds:[si],0 ;at end of environment?
|
||
|
jz gete80 ; yes, go fail the call
|
||
|
jmp short gete10 ; no, try try again
|
||
|
|
||
|
; Found the env variable, now skip the '=' and any spaces
|
||
|
|
||
|
gete50:
|
||
|
cmp byte ptr ds:[si],'=' ;when we get here, better be pointing
|
||
|
jnz gete30 ; at an '='
|
||
|
inc si
|
||
|
|
||
|
@@: cmp byte ptr ds:[si],' ' ;skip any optional blanks
|
||
|
jnz @f
|
||
|
inc si
|
||
|
jmp short @b
|
||
|
@@:
|
||
|
xor ax,ax ;set the Z flag
|
||
|
jmp short @f
|
||
|
|
||
|
gete80:
|
||
|
or ax,si ;pretty sure this clears Z
|
||
|
@@:
|
||
|
pop di
|
||
|
pop dx
|
||
|
pop ax
|
||
|
|
||
|
ret
|
||
|
|
||
|
GetEnv endp
|
||
|
|
||
|
; -------------------------------------------------------
|
||
|
|
||
|
DXCODE ends
|
||
|
|
||
|
;****************************************************************
|
||
|
end
|