]>
wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/COMMAND/PATH1.ASM
2 ; SCCSID = @(#)path1.asm 1.1 85/05/14
3 ; SCCSID = @(#)path1.asm 1.1 85/05/14
15 ;----------------------------------------------------------------------------
16 ; PATH.ASM contains the routines to perform pathname incovation. Path and
17 ; Parse share a temporary buffer and argv[] definitions. <Path_Search>,
18 ; given a pathname, attempts to find a corresponding executable or batch
19 ; file on disk. Directories specified in the user's search path will be
20 ; searched for a matching file, if a match is not found in the current
21 ; directory and if the pathname is actually only an MSDOS filename.
22 ; <Path_Search> assumes that the parsed command name can be found in
23 ; argv[0] -- in other words, <Parseline> should be executed prior to
24 ; <Path_Search>. Alternatively, the command name and appropriate
25 ; information could be placed in argv[0], or <Path_Search> could be
26 ; (easily) modified to make no assumptions about where its input is found.
27 ; Please find enclosed yet another important routine, <Save_Args>, which
28 ; places the entire arg/argv[]/argbuf structure on a piece of newly
29 ; allocated memory. This is handy for for-loop processing, and anything
30 ; else that wants to save the whole shebang and then process other command
33 ; Alan L, OS/MSDOS August 15, 1983
36 ; <Path_Search>: argv[0].
37 ; <Save_Args>: bytes to allocate in addition to arg structure
39 ; <Path_Search>: success flag, best pathname match in EXECPATH.
40 ; <Save_Args>: success flag, segment address of new memory
42 ; * <Argv_calc> handily turns an array index into an absolute pointer.
43 ; The computation depends on the size of an argv[] element (arg_ele).
44 ; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
45 ; does not function as specified; see <Parseline> for more details.
46 ; * <Parseline> now knows about the flags the internals of COMMAND.COM
47 ; need to know about. This extra information is stored in a switch_flag
48 ; word with each command-line argument; the switches themselves will not
49 ; appear in the resulting arg structure.
50 ; * With the exception of CARRY, flags are generally preserved across calls.
54 DEBUGx equ FALSE
; prints out debug info
59 TRANDATA
SEGMENT PUBLIC BYTE ;AC000;
63 TRANSPACE
SEGMENT PUBLIC BYTE ;AC000;
65 EXTRN BADPMES_ptr
:word
68 EXTRN search_best_buf
:byte
69 EXTRN search_error
:word
70 EXTRN string_ptr_2
:word
74 TRANCODE
SEGMENT PUBLIC BYTE ;AC000;
76 assume
cs:trangroup
, ds:trangroup
, es:trangroup
, ss:nothing
79 ;------------------------------------------------------------------------------
80 ; PATH_SEARCH tries to find the file it's given, somewhere. An initial value
81 ; of *argv[0].argstartel == 0 implies that there is no command (empty line
82 ; or 'd:' or 'd:/'). This check is done in strip; otherwise, strip formats
83 ; the filename/pathname into tpbuf. Search(tpbuf) is executed to see if we
84 ; have a match, either in the current working directory if we were handed
85 ; a filename, or in the specified directory, given a pathname. If this call
86 ; fails, and we were given a pathname, then Path_Search fails. Otherwise,
87 ; Path_Crunch is repeatedly invoked on tpbuf[STARTEL] (if there's a drive
88 ; prefix, we want to skip it) for each pathstring in userpath. Success on
89 ; either the first invocation of search or on one of the succeeding calls
90 ; sets up the appropriate information for copying the successful pathname
91 ; prefix (if any) into the result buffer, followed by the successful filename
92 ; match (from [search_best_buf]). The result is returned in in EXECPATH.
94 ; argv[0] -- command name and associated information
96 ; AX -- non-zero indicates type of file found
97 ; EXECPATH -- successful pathname (AX non-zero)
99 ; 1) Uses the temporary buffer, tpbuf, from the parse routines.
100 ; 2) Some files are more equal than others. See search: for rankings.
101 ; 3) Path_Search terminates as soon as a call to search succeeds, even
102 ; if search returns an .exe or .bat.
103 ; 5) Clobbers dma address.
105 pbuflen equ
128 ; length of EXECPATH
106 path_sep_char equ
';'
108 TRANSPACE
SEGMENT PUBLIC BYTE ;AC000;
114 Procedure Path_Search
,NEAR
118 push DX ; could use a "stack 'em" instruction
123 test DS:arg
.argv
[0].argflags
, (MASK wildcard
) + (MASK sw_flag
)
127 jmp path_failure
; ambiguous commands not allowed
130 call store_pchar
; figure out the pathname separator
131 mov DX, OFFSET TRANGROUP
:fbuf
; clobber old dma value with
132 trap set_dma
; a pointer to our dma buffer
134 invoke find_path
; get a handle (ES:DI) on user path
135 mov DS:pathinfo
[0], ES ; and squirrel it away
136 mov DS:pathinfo
[2], DI ; "old" pathstring pointer
137 mov DS:pathinfo
[4], DI ; "new" pathstring pointer
140 mov BX, pbuflen
; copy/format argv[0] into temp buffer
141 mov SI, OFFSET TRANGROUP
:EXECPATH
143 jc path_failure_jmp
; if possible, of course
145 mov DX, SI ; search(EXECPATH, error_message)
146 mov [search_error
], OFFSET TRANGROUP
:BADDRV_ptr
147 invoke search
; must do at least one search
148 or AX, AX ; find anything?
149 jz path_noinit
; failure ... search farther
151 mov BP, AX ; success... save filetype code
152 mov DI, OFFSET TRANGROUP
:EXECPATH
153 mov SI, DS:arg
.argv
[0].argpointer
154 mov CX, DS:arg
.argv
[0].argstartel
155 sub CX, SI ; compute prefix bytes to copy
157 ; We have the number of bytes in the prefix (up to the final component).
158 ; We need to form the complete pathname including leading drive and current
161 ; Is there a drive letter present?
165 cmp cx,2 ; room for drive letter?
166 jb AddDrive
; no, stick it in
167 cmp [si+1],ah ; colon present?
168 jz MoveDrive
; yes, just move it
171 mov al,curdrv
; get current drive
172 add al,"A" ; convert to uppercase letter
179 sub cx,2 ; 2 bytes less to move
184 sub dl,"a"-1 ; convert to 1-based for current dir
186 ; Stick in beginning path char
191 ; Is there a leading /? If so, then no current dir copy is necessary.
192 ; Otherwise, get current dir for DL.
194 cmp cx,1 ; is there room for path char?
195 jb AddPath
; no, go add path
198 cmp al,psep_char
; is there a path separator?
199 jz MovePath
; yes, go move remainder of path
201 dec si ; undo the lodsb
205 mov si,di ; remainder of buffer
208 ; The previous current dir will succeed a previous find_first already worked.
210 ; Find end of string.
215 cmp byte ptr [di],0 ; root (empty dir string)?
216 jz MovePath
; yes, no need for path char
219 cmp byte ptr [dI],0 ; end of string?
224 ; Stick in a trailing path char
229 ; Move remaining part of path. Skip leading path char if present.
232 cmp [si],al ; first char a path char?
234 inc si ; move past leading char
235 dec cx ; drop from count
238 jcxz CopyDone
; no chars to move!
242 jmp path_success
; run off and form complete pathname
245 test DS:arg
.argv
[0].argflags
, MASK path_sep
246 jnz path_failure
; complete pathname specified ==> fail
248 mov BH, path_sep_char
; semicolon terminates pathstring
249 mov DX, DS:arg
.argv
[0].argstartel
; this is where the last element starts
250 sub DX, DS:arg
.argv
[0].argpointer
; form pointer into EXECPATH,
251 add DX, OFFSET TRANGROUP
:EXECPATH
; skipping over drive spec, if any
254 call path_crunch
; pcrunch(EXECPATH, pathinfo)
255 mov BP, AX ; save filetype code
257 lahf ; save flags, just in case
258 or BP, BP ; did path_crunch find anything?
260 sahf ; see? needed those flags, after all!
261 jnc path_loop
; is there anything left to the path?
265 ;; jmp short path_exit ; 3/3/KK
266 jmp path_exit
;AC000; 3/3/KK
268 path_found: ; pathinfo[] points to winner
269 mov DI, OFFSET TRANGROUP
:EXECPATH
270 mov CX, pathinfo
[4] ; "new" pointer -- end of string
271 mov SI, pathinfo
[2] ; "old" pointer -- beginning of string
275 ; Look at the pathname and expand . and .. if they are the first element
276 ; in the pathname (after the drive letter)
281 cmp Byte Ptr ES:[SI+2],'.' ; Look for Current dir at start of path
284 push CX ; Save pointer to end of string
286 mov [DI],AL ; Copy drive letter, :, and root char
287 mov AL, ES:[SI+1] ; to EXECPATH
291 push SI ; Save pointer to begining of string
292 mov DL,ES:[SI] ; Convert device letter for cur dir
295 mov SI,DI ; pointer to EXECPATH
296 add SI, 3 ; Don't wipe out drive and root info
298 invoke DStrlen
; Determine length of present info
299 add SI,CX ; Don't copy over drive and root info
301 mov DI,SI ; Point to end of target string
302 pop SI ; Restore pointer to begining of string
303 add SI, 3 ; Point past drive letter, :, .
304 pop CX ; Restore pointer to end of string
308 sub CX, SI ; yields character count
309 push DS ; time to switch segments
310 push pathinfo
[0] ; string lives in this segment
313 ;; rep movsb 3/3/KK ; copy the prefix path into EXECPATH
315 Kloop: ;AN000; 3/3/KK
318 invoke testkanj
;AN000; 3/3/KK
319 jz NotKanj1
;AN000; 3/3/KK
320 dec cx ;AN000; 3/3/KK
321 JCXZ PopDone
;AN000; Ignore boundary error 3/3/KK
323 dec cx ;AN000; 3/3/KK
324 cmp cx,1 ;AN000; One char (the terminator) left ? 3/3/KK
325 ja Kloop
;AN000; no. 3/3/KK
327 PopDone: ;AN000; 3/3/KK
328 POP DS ;AN000; Yes ES:DI->terminator, last char is 3/3/KK
329 mov AL, psep_char
;AN000; KANJI 3/3/KK
330 jmp Short path_store
;AN000; 3/3/KK
334 pop DS ; return to our segment
335 dec DI ; overwrite terminator
336 mov AL, psep_char
; with a pathname separator
337 cmp al,byte ptr [di-1]
340 path_store: ;AN000; 3/3/KK
344 mov SI, OFFSET TRANGROUP
:search_best_buf
348 lodsb ; append winning filename to path
349 stosb ; (including terminating null)
352 mov AX, BP ; retrieve filetype code
358 pop SI ; chill out...
366 ;----------------------------------------------------------------------------
367 ; STORE_PCHAR determines the pathname-element separator and squirrels
368 ; it away. In other words, must we say '/bin/ls' or '\bin\ls'?
372 ; * Uses <psep_char>, defined in <path_search>.
375 Procedure Store_PChar
,NEAR
379 mov AL, '/' ; is the pathname-element separator
380 invoke pathchrcmp
; a regular slash?
381 jz store_slash
; if yes, remember slash
383 mov [psep_char], al ; otherwise, remember back-slash
393 ;----------------------------------------------------------------------------
396 ;----------------------------------------------------------------------------
397 ; PATH_CRUNCH takes a prefix from a prefix string, and a suffix from
398 ; EXECPATH, and smooshes them into tpbuf. The caller may supply an
399 ; additional separator to use for breaking up the path-string. Null is the
400 ; default. Once the user-string has been formed, search is invoked to see
403 ; BH -- additional terminator character
404 ; SI -- pointer into pathstring to be dissected
405 ; DX -- pointer to stripped filename
407 ; AX -- non-zero (file type), zero (nothing found)
408 ; SI -- moves along pathstring from call to call
409 ; [search_best_buf] -- name of best file (AX non-zero)
410 ; [tpbuf] -- clobbered
412 ; * Implicit in this code is the ability to specify when to search
413 ; the current directory (if at all) through the PATH defined by
414 ; the user, a la UNIX (e.g., PATH=;c:\bin;c:\etc searches the
415 ; current directory before the bin and etc directories of drive c).
417 Procedure Path_Crunch,NEAR
425 call store_pchar ; figure out pathname separator
426 mov DI, OFFSET TRANGROUP:tpbuf ; destination of concatenated string
427 mov SI, pathinfo[4] ; "new" pointer to start with
428 mov pathinfo[2], SI ; becomes "old" pointer
429 push DS ; save old segment pointer
430 push pathinfo[0] ; replace with pointer to userpath's
432 xor cl,cl ;AN000; clear flag for later use 3/3/KK
435 lodsb ; get a pathname byte
436 or al,al ; check for terminator(s)
437 jz path_seg ; null terminates segment & pathstring
439 jz path_seg ; BH terminates a pathstring segment
440 invoke testkanj ;AN000; 3/3/KK
441 jz NotKanj2 ;AN000; 3/3/KK
444 MOV CL,1 ;AN000; CL=1 means latest stored char is DBCS 3/3/KK
445 jmp path_cr_copy ;AN000; 3/3/KK
447 NotKanj2: ;AN000; 3/3/KK
448 xor cl,cl ;AN000; CL=0 means latest stored char is SBCS 3/3/KK
449 stosb ; save byte in concat buffer
450 jmp path_cr_copy ; loop until we see a terminator
453 pop DS ; restore old data segment
454 mov pathinfo[4], SI ; save "new" pointer for next time
455 mov BL, AL ; remember if we saw null or not...
456 ;;; REMOVE NEXT 3 LINES FOR CURDIR SPEC
457 xor AX, AX ; in case nothing in pathstr...
458 cmp DI, OFFSET TRANGROUP:tpbuf ; was there really anything in pathstr?
459 je path_cr_leave ; if nothing was copied, pathstr empty
461 path_cr_look: ; form complete pathname
462 mov al, psep_char ; add pathname separator for suffix
463 or cl,cl ;AN000; 3/3/KK
464 jnz path_cr_store ;AN000; this is a trailing byte of ECS code 3/3/KK
465 cmp al,byte ptr [di-1]
468 path_cr_store: ;AN000; 3/3/KK
475 lodsb ; tack the stripped filename onto
476 stosb ; the end of the path, up to and
477 or AL, AL ; including the terminating null
479 mov DX, OFFSET TRANGROUP:tpbuf ; and look for an appropriate file...
480 mov [search_error], OFFSET TRANGROUP:BADPMES_ptr
481 invoke search ; results are in AX & search_best_buf
484 or BL, BL ; did we finish off the pathstring?
485 jz path_cr_empty ; null in BL means all gone...
486 popf ; otherwise, plenty left
488 jmp short path_cr_exit
503 ;----------------------------------------------------------------------------