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