summaryrefslogtreecommitdiff
path: root/v4.0/src/CMD/COMMAND/PATH1.ASM
diff options
context:
space:
mode:
authorGravatar Mark Zbikowski2024-04-25 21:24:10 +0100
committerGravatar Microsoft Open Source2024-04-25 22:32:27 +0000
commit2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch)
tree80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0/src/CMD/COMMAND/PATH1.ASM
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0/src/CMD/COMMAND/PATH1.ASM')
-rw-r--r--v4.0/src/CMD/COMMAND/PATH1.ASM507
1 files changed, 507 insertions, 0 deletions
diff --git a/v4.0/src/CMD/COMMAND/PATH1.ASM b/v4.0/src/CMD/COMMAND/PATH1.ASM
new file mode 100644
index 0000000..4567174
--- /dev/null
+++ b/v4.0/src/CMD/COMMAND/PATH1.ASM
@@ -0,0 +1,507 @@
1 page 80,132
2; SCCSID = @(#)path1.asm 1.1 85/05/14
3; SCCSID = @(#)path1.asm 1.1 85/05/14
4.sall
5.xlist
6.xcref
7INCLUDE DOSSYM.INC
8 include comsw.asm
9 include comseg.asm
10 include comequ.asm
11.list
12.cref
13
14break <Path.Asm>
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
31; lines.
32;
33; Alan L, OS/MSDOS August 15, 1983
34;
35; ENTRY:
36; <Path_Search>: argv[0].
37; <Save_Args>: bytes to allocate in addition to arg structure
38; EXIT:
39; <Path_Search>: success flag, best pathname match in EXECPATH.
40; <Save_Args>: success flag, segment address of new memory
41; NOTE(S):
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.
51;---------------
52; CONSTANTS:
53;---------------
54 DEBUGx equ FALSE ; prints out debug info
55;---------------
56; DATA:
57;---------------
58
59TRANDATA SEGMENT PUBLIC BYTE ;AC000;
60 EXTRN baddrv_ptr:word
61TRANDATA ENDS
62
63TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
64 EXTRN arg:byte
65 EXTRN BADPMES_ptr:word
66 EXTRN curdrv:byte
67 EXTRN EXECPATH:byte
68 EXTRN search_best_buf:byte
69 EXTRN search_error:word
70 EXTRN string_ptr_2:word
71 EXTRN tpbuf:byte
72TRANSPACE ENDS
73
74TRANCODE SEGMENT PUBLIC BYTE ;AC000;
75
76assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
77
78break <Path_Search>
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.
93; ENTRY:
94; argv[0] -- command name and associated information
95; EXIT:
96; AX -- non-zero indicates type of file found
97; EXECPATH -- successful pathname (AX non-zero)
98; NOTE(S):
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.
104
105pbuflen equ 128 ; length of EXECPATH
106path_sep_char equ ';'
107
108TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
109 EXTRN fbuf:byte
110 EXTRN pathinfo:word
111 EXTRN psep_char:byte
112TRANSPACE ENDS
113
114Procedure Path_Search,NEAR
115
116 push BX
117 push CX
118 push DX ; could use a "stack 'em" instruction
119 push SI
120 push DI
121 push BP
122 pushf
123 test DS:arg.argv[0].argflags, (MASK wildcard) + (MASK sw_flag)
124 jz path_search_ok
125
126path_failure_jmp:
127 jmp path_failure ; ambiguous commands not allowed
128
129path_search_ok:
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
133 push ES
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
138 pop ES
139
140 mov BX, pbuflen ; copy/format argv[0] into temp buffer
141 mov SI, OFFSET TRANGROUP:EXECPATH
142 invoke strip
143 jc path_failure_jmp ; if possible, of course
144
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
150
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
156;
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
159; directory.
160;
161; Is there a drive letter present?
162;
163
164 mov ah,':'
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
169
170AddDrive:
171 mov al,curdrv ; get current drive
172 add al,"A" ; convert to uppercase letter
173 stosw ; store d:
174 jmp short CheckPath
175
176MoveDrive:
177 lodsw ; move d:
178 stosw
179 sub cx,2 ; 2 bytes less to move
180
181CheckPath:
182 or al,20h
183 mov dl,al
184 sub dl,"a"-1 ; convert to 1-based for current dir
185;
186; Stick in beginning path char
187;
188 mov al,psep_char
189 stosb
190;
191; Is there a leading /? If so, then no current dir copy is necessary.
192; Otherwise, get current dir for DL.
193;
194 cmp cx,1 ; is there room for path char?
195 jb AddPath ; no, go add path
196 lodsb
197 dec cx
198 cmp al,psep_char ; is there a path separator?
199 jz MovePath ; yes, go move remainder of path
200 inc cx
201 dec si ; undo the lodsb
202
203AddPath:
204 SaveReg <SI>
205 mov si,di ; remainder of buffer
206 trap Current_dir
207;
208; The previous current dir will succeed a previous find_first already worked.
209;
210; Find end of string.
211;
212 mov di,si
213 RestoreReg <SI>
214 mov al,psep_char
215 cmp byte ptr [di],0 ; root (empty dir string)?
216 jz MovePath ; yes, no need for path char
217
218ScanEnd:
219 cmp byte ptr [dI],0 ; end of string?
220 jz FoundEnd
221 inc di
222 jmp ScanEnd
223;
224; Stick in a trailing path char
225;
226FoundEnd:
227 stosb
228;
229; Move remaining part of path. Skip leading path char if present.
230;
231MovePath:
232 cmp [si],al ; first char a path char?
233 jnz CopyPath
234 inc si ; move past leading char
235 dec cx ; drop from count
236
237CopyPath:
238 jcxz CopyDone ; no chars to move!
239 rep movsb
240
241CopyDone:
242 jmp path_success ; run off and form complete pathname
243
244path_noinit:
245 test DS:arg.argv[0].argflags, MASK path_sep
246 jnz path_failure ; complete pathname specified ==> fail
247
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
252
253path_loop:
254 call path_crunch ; pcrunch(EXECPATH, pathinfo)
255 mov BP, AX ; save filetype code
256
257 lahf ; save flags, just in case
258 or BP, BP ; did path_crunch find anything?
259 jne path_found
260 sahf ; see? needed those flags, after all!
261 jnc path_loop ; is there anything left to the path?
262
263path_failure:
264 xor AX, AX
265;; jmp short path_exit ; 3/3/KK
266 jmp path_exit ;AC000; 3/3/KK
267
268path_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
272
273;
274; BAS Nov 20/84
275; Look at the pathname and expand . and .. if they are the first element
276; in the pathname (after the drive letter)
277;
278 push ES
279 push pathinfo[0]
280 pop ES
281 cmp Byte Ptr ES:[SI+2],'.' ; Look for Current dir at start of path
282 jnz path_cpy
283
284 push CX ; Save pointer to end of string
285 mov AL, ES:[SI]
286 mov [DI],AL ; Copy drive letter, :, and root char
287 mov AL, ES:[SI+1] ; to EXECPATH
288 mov [DI+1],AL
289 mov AL,psep_char
290 mov [DI+2],AL
291 push SI ; Save pointer to begining of string
292 mov DL,ES:[SI] ; Convert device letter for cur dir
293 or DL,20h
294 sub DL,"a"-1
295 mov SI,DI ; pointer to EXECPATH
296 add SI, 3 ; Don't wipe out drive and root info
297 trap Current_dir
298 invoke DStrlen ; Determine length of present info
299 add SI,CX ; Don't copy over drive and root info
300 dec SI
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
305
306path_cpy:
307 pop ES
308 sub CX, SI ; yields character count
309 push DS ; time to switch segments
310 push pathinfo[0] ; string lives in this segment
311 pop DS
312 cld
313;; rep movsb 3/3/KK ; copy the prefix path into EXECPATH
314
315Kloop: ;AN000; 3/3/KK
316 lodsb ;AN000; 3/3/KK
317 stosb ;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
322 movsb ;AN000; 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
326
327PopDone: ;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
331
332NotKanj1:
333 loop Kloop
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]
338 jz path_success
339
340path_store: ;AN000; 3/3/KK
341 stosb
342
343path_success:
344 mov SI, OFFSET TRANGROUP:search_best_buf
345 xor CX, CX
346
347path_succ_loop:
348 lodsb ; append winning filename to path
349 stosb ; (including terminating null)
350 or al,al
351 jnz path_succ_loop
352 mov AX, BP ; retrieve filetype code
353
354path_exit:
355 popf
356 pop BP
357 pop DI
358 pop SI ; chill out...
359 pop DX
360 pop CX
361 pop BX
362 ret
363EndProc Path_Search
364
365break <Store_Pchar>
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'?
369; ENTRY:
370; EXIT:
371; NOTE(S):
372; * Uses <psep_char>, defined in <path_search>.
373;---------------
374;---------------
375Procedure Store_PChar,NEAR
376;---------------
377
378 push AX
379 mov AL, '/' ; is the pathname-element separator
380 invoke pathchrcmp ; a regular slash?
381 jz store_slash ; if yes, remember slash
382 mov al,'\'
383 mov [psep_char], al ; otherwise, remember back-slash
384 pop ax
385 ret
386
387store_slash:
388 mov [psep_char], al
389 pop ax
390 return
391;---------------
392EndProc Store_Pchar
393;----------------------------------------------------------------------------
394
395break <Path_Crunch>
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
401; what's out there.
402; ENTRY:
403; BH -- additional terminator character
404; SI -- pointer into pathstring to be dissected
405; DX -- pointer to stripped filename
406; EXIT:
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
411; NOTE(S):
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).
416;---------------
417Procedure Path_Crunch,NEAR
418;---------------
419 push BX
420 push CX
421 push DX
422 push DI
423 push SI
424 pushf
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
431 pop DS ; segment
432 xor cl,cl ;AN000; clear flag for later use 3/3/KK
433
434path_cr_copy:
435 lodsb ; get a pathname byte
436 or al,al ; check for terminator(s)
437 jz path_seg ; null terminates segment & pathstring
438 cmp AL, BH
439 jz path_seg ; BH terminates a pathstring segment
440 invoke testkanj ;AN000; 3/3/KK
441 jz NotKanj2 ;AN000; 3/3/KK
442 stosb ;AN000; 3/3/KK
443 movsb ;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
446
447NotKanj2: ;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
451
452path_seg:
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
460
461path_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]
466 jz path_cr_l1
467
468path_cr_store: ;AN000; 3/3/KK
469 stosb
470
471path_cr_l1:
472 mov SI, DX
473
474path_cr_l2:
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
478 jnz path_cr_l2
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
482
483path_cr_leave:
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
487 clc
488 jmp short path_cr_exit
489
490path_cr_empty:
491 popf
492 stc
493
494path_cr_exit:
495 pop SI
496 pop DI
497 pop DX
498 pop CX
499 pop BX
500 ret
501;---------------
502EndProc Path_Crunch
503;----------------------------------------------------------------------------
504
505
506trancode ends
507END