title Path Searching Routines ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1993 ; * All Rights Reserved. ; */ Page ,132 ; PATH.ASM - Code to search the environment for a particular data string, ; and to search the path for a particular file. Adapted from the original ; COMMAND.COM version. ; ; Routines supported: ; Find_in_Environment - locate the start of a given string ; in the environment ; Path_Crunch - concantenates a file name with a directory path from ; the PATH environment variable ; Search - Finds executable or other files, given a base name ; include dossym.inc include curdir.inc include find.inc include pdb.inc include syscall.inc DATA segment para public 'DATA' Path_str db "PATH=" Path_str_size equ $ - offset Path_Str Comspec_str db "COMSPEC=" Comspec_str_size equ $ - offset Comspec_str comext db ".COM",0 exeext db ".EXE",0 DATA ends CODE segment para public 'CODE' assume cs:CODE,ds:DATA IFDEF DBCS extrn IsDBCSLeadByte:near ENDIF ;---------------------------------------------------------------------------- ; Path_Crunch - takes a pointer into a environment PATH string and a file ; name, and sticks them together, for subsequent searching. ; ; ENTRY: ; BH -- additional terminator character (i.e., ';') ; DS:SI -- pointer into pathstring to be dissected ; ES:DI -- buffer to store target name ; DX -- pointer to filename ; EXIT: ; SI -- moves along pathstring from call to call ; ES:DI -- filled in with concatenated name ; Carry set if end of path string has been reached. ; ;--------------- Path_Crunch PROC NEAR public Path_Crunch ;--------------- assume ds:nothing assume es:DATA IFDEF DBCS xor cl,cl ; clear flag for later use 3/3/KK ENDIF path_cr_copy: lodsb ; get a pathname byte or al,al ; check for terminator(s) jz path_seg ; null terminates segment & pathstring cmp AL, BH jz path_seg ; BH terminates a pathstring segment IFDEF DBCS invoke IsDBCSLeadByte ; jnz NotKanj2 ; stosb ; movsb ; MOV CL,1 ; CL=1 means latest stored char is DBCS jmp path_cr_copy ; NotKanj2: ; xor cl,cl ; CL=0 means latest stored char is SBCS ENDIF stosb ; save byte in concat buffer jmp path_cr_copy ; loop until we see a terminator path_seg: push si ; save resting place in env. seg. mov BL, AL ; remember if we saw null or not... path_cr_look: ; form complete pathname mov al, '\' ; add pathname separator for suffix IFDEF DBCS or cl,cl ; jnz path_cr_store ; this is a trailing byte of ECS code 3/3/KK ENDIF cmp al,es:byte ptr [di-1] jz path_cr_l1 path_cr_store: stosb path_cr_l1: mov SI, DX path_cr_l2: lods byte ptr es:[si] ; tack the stripped filename onto stosb ; the end of the path, up to and or AL, AL ; including the terminating null jnz path_cr_l2 path_cr_leave: or BL, BL ; did we finish off the pathstring? clc jnz path_cr_exit ; null in BL means all gone... cmc path_cr_exit: pop si ; retrieve ret assume es:nothing ;--------------- Path_Crunch endp ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; SEARCH, when given a pathname, attempts to find a file with ; one of the following extensions: .com, .exe (highest to ; lowest priority). Where conflicts arise, the extension with ; the highest priority is favored. ; ENTRY: ; DX -- pointer to null-terminated pathname ; BX -- dma buffer for findfirst/next ; AL -- 0 if we should look for .COM and .EXE extensions ; 1 if extensions is pre-specified ; EXIT: ; AX -- 8) file found with .com extension, or file with ; pre-specified extension found ; 4) file found with .exe extension ; 0) no such file to be found ; DX -- points to resolved path name ; DS -- DATA ; NOTES: ; 1) Requires caller to have allocated executed a setdma. ; ;--------------- ; CONSTANTS: ;--------------- search_attr equ attr_read_only+attr_hidden search_file_not_found equ 0 search_com equ 8 search_exe equ 4 fname_len equ 8 fname_max_len equ 23 dot equ '.' wildchar equ '?' search_best db (?) ;--------------- Search PROC NEAR public Search ;--------------- push si ; push ax ; save extension flag mov DI, DX ; working copy of pathname mov CX, search_attr ; filetypes to search for mov ah, Find_First ; request first match, if any int 21h pop ax jc search_no_file or al,al ; looking for specific ext? jz search_no_ext ; no, jump mov search_best,search_com ; report we found best match jmp short search_file_found ; yes, found it search_no_ext: mov search_best, search_file_not_found search_loop: call search_ftype ; determine if .com, &c... cmp AL, search_best ; better than what we've found so far? jle search_next ; no, look for another mov search_best, AL ; found something... save its code cmp AL, search_com ; have we found the best of all? je search_done search_next: ; keep on looking mov CX, search_attr mov ah, Find_Next ; next match int 21h jnc search_loop search_done: ; it's all over with... cmp search_best, search_file_not_found je search_no_file cmp search_best, search_com mov si, offset comext je search_move_ext mov si, offset exeext search_move_ext: mov di, dx mov al, '.' mov cx, DIRSTRLEN rep scasb dec di movsw movsw search_file_found: mov al, search_best jmp short search_exit search_no_file: ; couldn't find a match mov AX, search_file_not_found search_exit: pop si ret Search endp ;---------------------------------------------------------------------------- ;---------------------------------------------------------------------------- ; SEARCH_FTYPE determines the type of a file by examining its extension. ; ENTRY: ; BX -- dma buffer containing filename ; EXIT: ; AL -- file code, as given in search header ;--------------- Search_Ftype PROC NEAR public Search_Ftype push DI mov AL, search_file_not_found ; find the end of the filename mov DI, BX add di,Find_Buf_Pname mov CX, fname_max_len cld repnz scasb ; search for the terminating null jnz ftype_exit ; weird... no null byte at end ; ; Scan backwards to find the start of the extension ; dec di ; point back to null mov cx, 5 ; . + E + X + T + null std ; scan back mov al, '.' repnz scasb jnz ftype_exit ; must not be any extension inc di ; point to start of extension cld ; ; Compare .COM ; mov si,offset comext mov ax,di cmpsw jnz ftype_exe cmpsw jnz ftype_exe mov AL, search_com ; success! jmp short ftype_exit ; ; Compare .EXE ; ftype_exe: ; still looking... now for '.exe' mov di,ax mov si,offset exeext cmpsw jnz ftype_fail cmpsw jnz ftype_fail mov AL, search_exe ; success! jmp short ftype_exit ftype_fail: ; file doesn't match what we need mov al,search_file_not_found ftype_exit: pop DI ret Search_Ftype endp ;---------------------------------------------------------------------------- ; ; Find_Comspec_In_Environment - find the beginning of the COMSPEC string ; Entry : DS = DATA ; ES = PSP ; Exit : ES:DI => start of Comspec path ; FIND_COMSPEC_IN_environment PROC NEAR public Find_Comspec_In_Environment lea si,Comspec_str mov cx,Comspec_str_size ; cx = length of name jmp short Find_in_Environment Find_Comspec_in_Environment endp ;---------------------------------------------------------------------------- ; ; Find_Path_In_Environment - find the beginning of the PATH string ; Entry : DS = DATA ; ES = PSP ; Exit : ES:DI => start of Path directory list ; FIND_PATH_IN_environment PROC NEAR public Find_Path_In_Environment lea si,Path_str mov cx,Path_str_size ; cx = length of name ; fall through to following Find_Path_in_Environment endp ; Find_In_Environment - locate a given string in the environment ; ; Input : SI = name to find in environment ; CX = length of name ; DS = DATA ; ES = PSP segment ; ; Output: ES:DI points to the arguments in the environment ; carry is set if name not found ; Find_in_Environment PROC NEAR public Find_In_Environment cld xor di,di mov ax,es:[di].PDB_Environ or ax,ax ; is there an environment? jz find_nf_exit ; no, quit now mov es,ax assume es:nothing find1: push si push cx ; save starting values find11: ifdef dbcs lodsb call IsDBCSLeadByte jnz notkanj3 dec si lodsw inc di inc di cmp ax,es:[di-2] jnz find12 dec cx loop find11 jmp short find12 notkanj3: inc di cmp al,es:[di-1] jnz find12 loop find11 else ;dbcs repe cmpsb endif ;dbcs find12: pop dx pop si ; clear stack jz find_exit dec di xor al,al ; scan for a nul mov cx,100h ; arbitrary size repnz scasb cmp byte ptr es:[di],0 ; check for trailing null mov cx,dx ; original count back in CX jnz find1 find_nf_exit: stc ; indicate not found find_exit: ret Find_in_environment endp CODE ends end