You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
526 lines
16 KiB
526 lines
16 KiB
page ,132
|
|
;/*
|
|
; * Microsoft Confidential
|
|
; * Copyright (C) Microsoft Corporation 1991
|
|
; * All Rights Reserved.
|
|
; */
|
|
; SCCSID = @(#)path1.asm 1.1 85/05/14
|
|
; SCCSID = @(#)path1.asm 1.1 85/05/14
|
|
.sall
|
|
.xlist
|
|
.xcref
|
|
include dossym.inc
|
|
include syscall.inc
|
|
include comsw.asm
|
|
include comseg.asm
|
|
include comequ.asm
|
|
.list
|
|
.cref
|
|
|
|
break <Path.Asm>
|
|
;----------------------------------------------------------------------------
|
|
; PATH.ASM contains the routines to perform pathname incovation. Path and
|
|
; Parse share a temporary buffer and argv[] definitions. <Path_Search>,
|
|
; given a pathname, attempts to find a corresponding executable or batch
|
|
; file on disk. Directories specified in the user's search path will be
|
|
; searched for a matching file, if a match is not found in the current
|
|
; directory and if the pathname is actually only an MSDOS filename.
|
|
; <Path_Search> assumes that the parsed command name can be found in
|
|
; argv[0] -- in other words, <Parseline> should be executed prior to
|
|
; <Path_Search>. Alternatively, the command name and appropriate
|
|
; information could be placed in argv[0], or <Path_Search> could be
|
|
; (easily) modified to make no assumptions about where its input is found.
|
|
; Please find enclosed yet another important routine, <Save_Args>, which
|
|
; places the entire arg/argv[]/argbuf structure on a piece of newly
|
|
; allocated memory. This is handy for for-loop processing, and anything
|
|
; else that wants to save the whole shebang and then process other command
|
|
; lines.
|
|
;
|
|
; Alan L, OS/MSDOS August 15, 1983
|
|
;
|
|
; ENTRY:
|
|
; <Path_Search>: argv[0].
|
|
; <Save_Args>: bytes to allocate in addition to arg structure
|
|
; EXIT:
|
|
; <Path_Search>: success flag, best pathname match in EXECPATH.
|
|
; <Save_Args>: success flag, segment address of new memory
|
|
; NOTE(S):
|
|
; * <Argv_calc> handily turns an array index into an absolute pointer.
|
|
; The computation depends on the size of an argv[] element (arg_ele).
|
|
; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
|
|
; does not function as specified; see <Parseline> for more details.
|
|
; * <Parseline> now knows about the flags the internals of COMMAND.COM
|
|
; need to know about. This extra information is stored in a switch_flag
|
|
; word with each command-line argument; the switches themselves will not
|
|
; appear in the resulting arg structure.
|
|
; * With the exception of CARRY, flags are generally preserved across calls.
|
|
;---------------
|
|
; CONSTANTS:
|
|
;---------------
|
|
DEBUGx equ FALSE ; prints out debug info
|
|
;---------------
|
|
; DATA:
|
|
;---------------
|
|
|
|
TRANDATA SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN baddrv_ptr:word
|
|
TRANDATA ENDS
|
|
|
|
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN arg:byte
|
|
EXTRN BADPMES_ptr:word
|
|
EXTRN curdrv:byte
|
|
EXTRN EXECPATH:byte
|
|
EXTRN search_best_buf:byte
|
|
EXTRN search_error:word
|
|
EXTRN string_ptr_2:word
|
|
EXTRN tpbuf:byte
|
|
TRANSPACE ENDS
|
|
|
|
TRANCODE SEGMENT PUBLIC BYTE ;AC000;
|
|
|
|
assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
|
|
|
|
break <Path_Search>
|
|
;------------------------------------------------------------------------------
|
|
; PATH_SEARCH tries to find the file it's given, somewhere. An initial value
|
|
; of *argv[0].argstartel == 0 implies that there is no command (empty line
|
|
; or 'd:' or 'd:/'). This check is done in strip; otherwise, strip formats
|
|
; the filename/pathname into tpbuf. Search(tpbuf) is executed to see if we
|
|
; have a match, either in the current working directory if we were handed
|
|
; a filename, or in the specified directory, given a pathname. If this call
|
|
; fails, and we were given a pathname, then Path_Search fails. Otherwise,
|
|
; Path_Crunch is repeatedly invoked on tpbuf[STARTEL] (if there's a drive
|
|
; prefix, we want to skip it) for each pathstring in userpath. Success on
|
|
; either the first invocation of search or on one of the succeeding calls
|
|
; sets up the appropriate information for copying the successful pathname
|
|
; prefix (if any) into the result buffer, followed by the successful filename
|
|
; match (from [search_best_buf]). The result is returned in in EXECPATH.
|
|
; ENTRY:
|
|
; argv[0] -- command name and associated information
|
|
; EXIT:
|
|
; AX -- non-zero indicates type of file found
|
|
; EXECPATH -- successful pathname (AX non-zero)
|
|
; NOTE(S):
|
|
; 1) Uses the temporary buffer, tpbuf, from the parse routines.
|
|
; 2) Some files are more equal than others. See search: for rankings.
|
|
; 3) Path_Search terminates as soon as a call to search succeeds, even
|
|
; if search returns an .exe or .bat.
|
|
; 5) Clobbers dma address.
|
|
|
|
pbuflen equ EXECPATHLEN ; len EXECPATH - ntvdm extended
|
|
path_sep_char equ ';'
|
|
|
|
TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
|
|
EXTRN fbuf:byte
|
|
EXTRN pathinfo:word
|
|
EXTRN psep_char:byte
|
|
TRANSPACE ENDS
|
|
|
|
Procedure Path_Search,NEAR
|
|
assume ds:trangroup, es:trangroup
|
|
|
|
push BX
|
|
push CX
|
|
push DX ; could use a "stack 'em" instruction
|
|
push SI
|
|
push DI
|
|
push BP
|
|
pushf
|
|
test DS:arg.argv[0].argflags, (MASK wildcard) + (MASK sw_flag)
|
|
jz path_search_ok
|
|
|
|
path_failure_jmp:
|
|
jmp path_failure ; ambiguous commands not allowed
|
|
|
|
path_search_ok:
|
|
call store_pchar ; figure out the pathname separator
|
|
mov DX, OFFSET TRANGROUP:fbuf ; clobber old dma value with
|
|
trap set_dma ; a pointer to our dma buffer
|
|
push ES
|
|
invoke find_path ; get a handle (ES:DI) on user path
|
|
mov DS:pathinfo[0], ES ; and squirrel it away
|
|
mov DS:pathinfo[2], DI ; "old" pathstring pointer
|
|
mov DS:pathinfo[4], DI ; "new" pathstring pointer
|
|
pop ES
|
|
|
|
mov BX, pbuflen ; copy/format argv[0] into temp buffer
|
|
mov SI, OFFSET TRANGROUP:EXECPATH
|
|
invoke strip
|
|
jc path_failure_jmp ; if possible, of course
|
|
|
|
mov DX, SI ; search(EXECPATH, error_message)
|
|
mov [search_error], OFFSET TRANGROUP:BADDRV_ptr
|
|
invoke search ; must do at least one search
|
|
or AX, AX ; find anything?
|
|
jz path_noinit ; failure ... search farther
|
|
|
|
mov BP, AX ; success... save filetype code
|
|
mov DI, OFFSET TRANGROUP:EXECPATH
|
|
mov SI, DS:arg.argv[0].argpointer
|
|
mov CX, DS:arg.argv[0].argstartel
|
|
sub CX, SI ; compute prefix bytes to copy
|
|
;
|
|
; We have the number of bytes in the prefix (up to the final component).
|
|
; We need to form the complete pathname including leading drive and current
|
|
; directory.
|
|
;
|
|
; Is there a drive letter present?
|
|
;
|
|
cmp word ptr [si], 05c5ch ; If a UNC name, copy straight in
|
|
je CopyPath
|
|
|
|
mov ah,':'
|
|
cmp cx,2 ; room for drive letter?
|
|
jb AddDrive ; no, stick it in
|
|
cmp [si+1],ah ; colon present?
|
|
jz MoveDrive ; yes, just move it
|
|
|
|
AddDrive:
|
|
mov al,curdrv ; get current drive
|
|
add al,"A" ; convert to uppercase letter
|
|
stosw ; store d:
|
|
jmp short CheckPath
|
|
|
|
MoveDrive:
|
|
lodsw ; move d:
|
|
stosw
|
|
sub cx,2 ; 2 bytes less to move
|
|
|
|
CheckPath:
|
|
or al,20h
|
|
mov dl,al
|
|
sub dl,"a"-1 ; convert to 1-based for current dir
|
|
;
|
|
; Stick in beginning path char
|
|
;
|
|
mov al,psep_char
|
|
stosb
|
|
;
|
|
; Is there a leading /? If so, then no current dir copy is necessary.
|
|
; Otherwise, get current dir for DL.
|
|
;
|
|
cmp cx,1 ; is there room for path char?
|
|
jb AddPath ; no, go add path
|
|
lodsb
|
|
dec cx
|
|
cmp al,psep_char ; is there a path separator?
|
|
jz MovePath ; yes, go move remainder of path
|
|
inc cx
|
|
dec si ; undo the lodsb
|
|
|
|
AddPath:
|
|
SaveReg <SI>
|
|
mov si,di ; remainder of buffer
|
|
trap Current_dir
|
|
;
|
|
; The previous current dir will succeed a previous find_first already worked.
|
|
;
|
|
; Find end of string.
|
|
;
|
|
mov di,si
|
|
RestoreReg <SI>
|
|
mov al,psep_char
|
|
cmp byte ptr [di],0 ; root (empty dir string)?
|
|
jz MovePath ; yes, no need for path char
|
|
|
|
ScanEnd:
|
|
cmp byte ptr [dI],0 ; end of string?
|
|
jz FoundEnd
|
|
inc di
|
|
jmp ScanEnd
|
|
;
|
|
; Stick in a trailing path char
|
|
;
|
|
FoundEnd:
|
|
stosb
|
|
;
|
|
; Move remaining part of path. Skip leading path char if present.
|
|
;
|
|
MovePath:
|
|
cmp [si],al ; first char a path char?
|
|
jnz CopyPath
|
|
inc si ; move past leading char
|
|
dec cx ; drop from count
|
|
|
|
CopyPath:
|
|
jcxz CopyDone ; no chars to move!
|
|
rep movsb
|
|
|
|
CopyDone:
|
|
jmp path_success ; run off and form complete pathname
|
|
|
|
path_noinit:
|
|
test DS:arg.argv[0].argflags, MASK path_sep
|
|
jnz path_failure ; complete pathname specified ==> fail
|
|
|
|
mov BH, path_sep_char ; semicolon terminates pathstring
|
|
mov DX, DS:arg.argv[0].argstartel ; this is where the last element starts
|
|
sub DX, DS:arg.argv[0].argpointer ; form pointer into EXECPATH,
|
|
add DX, OFFSET TRANGROUP:EXECPATH ; skipping over drive spec, if any
|
|
|
|
path_loop:
|
|
call path_crunch ; pcrunch(EXECPATH, pathinfo)
|
|
mov BP, AX ; save filetype code
|
|
|
|
lahf ; save flags, just in case
|
|
or BP, BP ; did path_crunch find anything?
|
|
jne path_found
|
|
sahf ; see? needed those flags, after all!
|
|
jnc path_loop ; is there anything left to the path?
|
|
|
|
path_failure:
|
|
xor AX, AX
|
|
;; jmp short path_exit ; 3/3/KK
|
|
jmp path_exit ;AC000; 3/3/KK
|
|
|
|
path_found: ; pathinfo[] points to winner
|
|
mov DI, OFFSET TRANGROUP:EXECPATH
|
|
mov CX, pathinfo[4] ; "new" pointer -- end of string
|
|
mov SI, pathinfo[2] ; "old" pointer -- beginning of string
|
|
|
|
;
|
|
; BAS Nov 20/84
|
|
; Look at the pathname and expand . and .. if they are the first element
|
|
; in the pathname (after the drive letter)
|
|
;
|
|
push ES
|
|
push pathinfo[0]
|
|
pop ES
|
|
;SR;
|
|
; Oops! Gets fooled if path= \;..
|
|
; We should also check if a drive letter is really present
|
|
;
|
|
cmp Byte Ptr ES:[SI+2],'.' ; Look for Current dir at start of path
|
|
jnz path_cpy
|
|
|
|
cmp byte ptr es:[si+1],':' ;does path have drive letter?
|
|
jnz path_cpy ;no, copy the path string
|
|
|
|
push CX ; Save pointer to end of string
|
|
mov AL, ES:[SI]
|
|
mov [DI],AL ; Copy drive letter, :, and root char
|
|
mov AL, ES:[SI+1] ; to EXECPATH
|
|
mov [DI+1],AL
|
|
mov AL,psep_char
|
|
mov [DI+2],AL
|
|
push SI ; Save pointer to begining of string
|
|
mov DL,ES:[SI] ; Convert device letter for cur dir
|
|
or DL,20h
|
|
sub DL,"a"-1
|
|
mov SI,DI ; pointer to EXECPATH
|
|
add SI, 3 ; Don't wipe out drive and root info
|
|
trap Current_dir
|
|
invoke DStrlen ; Determine length of present info
|
|
add SI,CX ; Don't copy over drive and root info
|
|
dec SI
|
|
mov DI,SI ; Point to end of target string
|
|
pop SI ; Restore pointer to begining of string
|
|
add SI, 3 ; Point past drive letter, :, .
|
|
pop CX ; Restore pointer to end of string
|
|
|
|
path_cpy:
|
|
pop ES
|
|
sub CX, SI ; yields character count
|
|
push DS ; time to switch segments
|
|
push pathinfo[0] ; string lives in this segment
|
|
pop DS
|
|
cld
|
|
;; rep movsb 3/3/KK ; copy the prefix path into EXECPATH
|
|
|
|
Kloop: ;AN000; 3/3/KK
|
|
lodsb ;AN000; 3/3/KK
|
|
stosb ;AN000; 3/3/KK
|
|
invoke testkanj ;AN000; 3/3/KK
|
|
jz NotKanj1 ;AN000; 3/3/KK
|
|
dec cx ;AN000; 3/3/KK
|
|
JCXZ PopDone ;AN000; Ignore boundary error 3/3/KK
|
|
movsb ;AN000; 3/3/KK
|
|
dec cx ;AN000; 3/3/KK
|
|
cmp cx,1 ;AN000; One char (the terminator) left ? 3/3/KK
|
|
ja Kloop ;AN000; no. 3/3/KK
|
|
|
|
PopDone: ;AN000; 3/3/KK
|
|
POP DS ;AN000; Yes ES:DI->terminator, last char is 3/3/KK
|
|
mov AL, psep_char ;AN000; KANJI 3/3/KK
|
|
jmp Short path_store ;AN000; 3/3/KK
|
|
|
|
NotKanj1:
|
|
loop Kloop
|
|
pop DS ; return to our segment
|
|
dec DI ; overwrite terminator
|
|
mov AL, psep_char ; with a pathname separator
|
|
cmp al,byte ptr [di-1]
|
|
jz path_success
|
|
|
|
path_store: ;AN000; 3/3/KK
|
|
stosb
|
|
|
|
path_success:
|
|
mov SI, OFFSET TRANGROUP:search_best_buf
|
|
xor CX, CX
|
|
|
|
path_succ_loop:
|
|
lodsb ; append winning filename to path
|
|
stosb ; (including terminating null)
|
|
or al,al
|
|
jnz path_succ_loop
|
|
mov AX, BP ; retrieve filetype code
|
|
|
|
path_exit:
|
|
popf
|
|
pop BP
|
|
pop DI
|
|
pop SI ; chill out...
|
|
pop DX
|
|
pop CX
|
|
pop BX
|
|
ret
|
|
EndProc Path_Search
|
|
|
|
break <Store_Pchar>
|
|
;----------------------------------------------------------------------------
|
|
; STORE_PCHAR determines the pathname-element separator and squirrels
|
|
; it away. In other words, must we say '/bin/ls' or '\bin\ls'?
|
|
; ENTRY:
|
|
; EXIT:
|
|
; NOTE(S):
|
|
; * Uses <psep_char>, defined in <path_search>.
|
|
;---------------
|
|
;---------------
|
|
Procedure Store_PChar,NEAR
|
|
;---------------
|
|
assume ds:trangroup, es:trangroup
|
|
|
|
push AX
|
|
mov AL, '/' ; is the pathname-element separator
|
|
invoke pathchrcmp ; a regular slash?
|
|
jz store_slash ; if yes, remember slash
|
|
mov al,'\'
|
|
mov [psep_char], al ; otherwise, remember back-slash
|
|
pop ax
|
|
ret
|
|
|
|
store_slash:
|
|
mov [psep_char], al
|
|
pop ax
|
|
return
|
|
;---------------
|
|
EndProc Store_Pchar
|
|
;----------------------------------------------------------------------------
|
|
|
|
break <Path_Crunch>
|
|
;----------------------------------------------------------------------------
|
|
; PATH_CRUNCH takes a prefix from a prefix string, and a suffix from
|
|
; EXECPATH, and smooshes them into tpbuf. The caller may supply an
|
|
; additional separator to use for breaking up the path-string. Null is the
|
|
; default. Once the user-string has been formed, search is invoked to see
|
|
; what's out there.
|
|
; ENTRY:
|
|
; BH -- additional terminator character
|
|
; SI -- pointer into pathstring to be dissected
|
|
; DX -- pointer to stripped filename
|
|
; EXIT:
|
|
; AX -- non-zero (file type), zero (nothing found)
|
|
; SI -- moves along pathstring from call to call
|
|
; [search_best_buf] -- name of best file (AX non-zero)
|
|
; [tpbuf] -- clobbered
|
|
; NOTE(S):
|
|
; * Implicit in this code is the ability to specify when to search
|
|
; the current directory (if at all) through the PATH defined by
|
|
; the user, a la UNIX (e.g., PATH=;c:\bin;c:\etc searches the
|
|
; current directory before the bin and etc directories of drive c).
|
|
;---------------
|
|
Procedure Path_Crunch,NEAR
|
|
;---------------
|
|
assume ds:trangroup, es:trangroup
|
|
push BX
|
|
push CX
|
|
push DX
|
|
push DI
|
|
push SI
|
|
pushf
|
|
call store_pchar ; figure out pathname separator
|
|
mov DI, OFFSET TRANGROUP:tpbuf ; destination of concatenated string
|
|
mov SI, pathinfo[4] ; "new" pointer to start with
|
|
mov pathinfo[2], SI ; becomes "old" pointer
|
|
push DS ; save old segment pointer
|
|
push pathinfo[0] ; replace with pointer to userpath's
|
|
pop DS ; segment
|
|
xor cl,cl ;AN000; clear flag for later use 3/3/KK
|
|
|
|
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
|
|
invoke testkanj ;AN000; 3/3/KK
|
|
jz NotKanj2 ;AN000; 3/3/KK
|
|
stosb ;AN000; 3/3/KK
|
|
movsb ;AN000; 3/3/KK
|
|
MOV CL,1 ;AN000; CL=1 means latest stored char is DBCS 3/3/KK
|
|
jmp path_cr_copy ;AN000; 3/3/KK
|
|
|
|
NotKanj2: ;AN000; 3/3/KK
|
|
xor cl,cl ;AN000; CL=0 means latest stored char is SBCS 3/3/KK
|
|
stosb ; save byte in concat buffer
|
|
jmp path_cr_copy ; loop until we see a terminator
|
|
|
|
path_seg:
|
|
pop DS ; restore old data segment
|
|
mov pathinfo[4], SI ; save "new" pointer for next time
|
|
mov BL, AL ; remember if we saw null or not...
|
|
;;; REMOVE NEXT 3 LINES FOR CURDIR SPEC
|
|
xor AX, AX ; in case nothing in pathstr...
|
|
cmp DI, OFFSET TRANGROUP:tpbuf ; was there really anything in pathstr?
|
|
je path_cr_leave ; if nothing was copied, pathstr empty
|
|
|
|
path_cr_look: ; form complete pathname
|
|
mov al, psep_char ; add pathname separator for suffix
|
|
or cl,cl ;AN000; 3/3/KK
|
|
jnz path_cr_store ;AN000; this is a trailing byte of ECS code 3/3/KK
|
|
cmp al,byte ptr [di-1]
|
|
jz path_cr_l1
|
|
|
|
path_cr_store: ;AN000; 3/3/KK
|
|
stosb
|
|
|
|
path_cr_l1:
|
|
mov SI, DX
|
|
|
|
path_cr_l2:
|
|
lodsb ; 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
|
|
mov DX, OFFSET TRANGROUP:tpbuf ; and look for an appropriate file...
|
|
mov [search_error], OFFSET TRANGROUP:BADPMES_ptr
|
|
invoke search ; results are in AX & search_best_buf
|
|
|
|
path_cr_leave:
|
|
or BL, BL ; did we finish off the pathstring?
|
|
jz path_cr_empty ; null in BL means all gone...
|
|
popf ; otherwise, plenty left
|
|
clc
|
|
jmp short path_cr_exit
|
|
|
|
path_cr_empty:
|
|
popf
|
|
stc
|
|
|
|
path_cr_exit:
|
|
pop SI
|
|
pop DI
|
|
pop DX
|
|
pop CX
|
|
pop BX
|
|
ret
|
|
;---------------
|
|
EndProc Path_Crunch
|
|
;----------------------------------------------------------------------------
|
|
|
|
|
|
trancode ends
|
|
END
|
|
|