]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/CMD/COMMAND/PATH2.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / CMD / COMMAND / PATH2.ASM
1 page 80,132
2 ; SCCSID = @(#)path2.asm 1.1 85/05/14
3 ; SCCSID = @(#)path2.asm 1.1 85/05/14
4 .sall
5 .xlist
6 .xcref
7 INCLUDE DOSSYM.INC
8 include comsw.asm
9 include comseg.asm
10 include comequ.asm
11 .list
12 .cref
13
14
15 DATARES SEGMENT PUBLIC BYTE
16 EXTRN FORFLAG:BYTE
17 DATARES ENDS
18
19
20 break <Path.Asm>
21 ;----------------------------------------------------------------------------
22 ; PATH.ASM contains the routines to perform pathname incovation. Path and
23 ; Parse share a temporary buffer and argv[] definitions. <Path_Search>,
24 ; given a pathname, attempts to find a corresponding executable or batch
25 ; file on disk. Directories specified in the user's search path will be
26 ; searched for a matching file, if a match is not found in the current
27 ; directory and if the pathname is actually only an MSDOS filename.
28 ; <Path_Search> assumes that the parsed command name can be found in
29 ; argv[0] -- in other words, <Parseline> should be executed prior to
30 ; <Path_Search>. Alternatively, the command name and appropriate
31 ; information could be placed in argv[0], or <Path_Search> could be
32 ; (easily) modified to make no assumptions about where its input is found.
33 ; Please find enclosed yet another important routine, <Save_Args>, which
34 ; places the entire arg/argv[]/argbuf structure on a piece of newly
35 ; allocated memory. This is handy for for-loop processing, and anything
36 ; else that wants to save the whole shebang and then process other command
37 ; lines.
38 ;
39 ; Alan L, OS/MSDOS August 15, 1983
40 ;
41 ; ENTRY:
42 ; <Path_Search>: argv[0].
43 ; <Save_Args>: bytes to allocate in addition to arg structure
44 ; EXIT:
45 ; <Path_Search>: success flag, best pathname match in EXECPATH.
46 ; <Save_Args>: success flag, segment address of new memory
47 ; NOTE(S):
48 ; * <Argv_calc> handily turns an array index into an absolute pointer.
49 ; The computation depends on the size of an argv[] element (arg_ele).
50 ; * <Parseline> calls <cparse> for chunks of the command line. <Cparse>
51 ; does not function as specified; see <Parseline> for more details.
52 ; * <Parseline> now knows about the flags the internals of COMMAND.COM
53 ; need to know about. This extra information is stored in a switch_flag
54 ; word with each command-line argument; the switches themselves will not
55 ; appear in the resulting arg structure.
56 ; * With the exception of CARRY, flags are generally preserved across calls.
57 ;---------------
58 ; CONSTANTS:
59 ;---------------
60 DEBUGx equ FALSE ; prints out debug info
61 ;---------------
62 ; DATA:
63 ;---------------
64
65 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
66 EXTRN arg:byte
67 EXTRN BADPMES_ptr:word
68 EXTRN curdrv:byte
69 EXTRN EXECPATH:byte
70 EXTRN ext_entered:byte ;AN005;
71 EXTRN fbuf:byte
72 EXTRN pathinfo:word
73 EXTRN psep_char:byte
74 EXTRN string_ptr_2:word
75 EXTRN tpbuf:byte
76 TRANSPACE ENDS
77
78 TRANCODE SEGMENT PUBLIC BYTE ;AC000;
79
80 assume cs:trangroup, ds:trangroup, es:trangroup, ss:nothing
81
82
83 break <Search>
84 ;----------------------------------------------------------------------------
85 ; SEARCH, when given a pathname, attempts to find a file with
86 ; one of the following extensions: .com, .exe, .bat (highest to
87 ; lowest priority). Where conflicts arise, the extension with
88 ; the highest priority is favored.
89 ; ENTRY:
90 ; DX -- pointer to null-terminated pathname
91 ; fbuf -- dma buffer for findfirst/next
92 ; EXIT:
93 ; AX -- 8) file found with .com extension
94 ; 4) file found with .exe extension
95 ; 2) file found with .bat extension
96 ; 0) no such file to be found
97 ; (if AX is non-zero:)
98 ; [search_best] identical to AX
99 ; [search_best_buf] null-terminated filename
100 ; NOTES:
101 ; 1) Requires caller to have allocated a dma buffer and executed a setdma.
102 ;---------------
103 ; CONSTANTS:
104 ;---------------
105 search_file_not_found equ 0
106 search_com equ 8
107 search_exe equ 4
108 search_bat equ 2
109 fname_len equ 8
110 fname_max_len equ 13
111 dot equ '.'
112 wildchar equ '?'
113
114 ;---------------
115 ; DATA:
116 ;---------------
117 TRANSPACE SEGMENT PUBLIC BYTE ;AC000;
118 EXTRN search_best:byte
119 EXTRN search_best_buf:byte
120 EXTRN search_curdir_buf:byte
121 EXTRN search_error:word
122 TRANSPACE ENDS
123
124 ;---------------
125 Procedure Search,NEAR
126 ;---------------
127 push CX
128 push DX
129 push DI
130 push SI
131 pushf
132
133 push DX ; check drivespec (save pname ptr)
134 mov DI, DX ; working copy of pathname
135 mov SI, OFFSET TRANGROUP:search_curdir_buf
136 xor DX, DX ; zero means current drive
137 cmp BYTE PTR [DI+1],':' ; is there a drive spec?
138 jne search_dir_check
139 mov DL, [DI] ; get the drive byte
140 and DL, NOT 20H ; uppercase the sucker
141 sub DL, '@' ; and convert to drive number
142
143 search_dir_check:
144 trap Current_Dir ; can we get the drive's current
145 pop DX ; directory? If we can't we'll
146 jc search_invalid_drive ; assume it's a bad drive...
147
148 mov CX, search_attr ; filetypes to search for
149 trap Find_First ; request first match, if any
150 jc search_no_file
151 mov search_best, search_file_not_found
152 mov [search_best_buf], ANULL ; nothing's been found, yet
153
154 search_loop:
155 call search_ftype ; determine if .com, &c...
156 cmp AL, search_best ; better than what we've found so far?
157 jle search_next ; no, look for another
158 mov search_best, AL ; found something... save its code
159 mov SI, OFFSET TRANGROUP:fbuf.find_buf_pname
160 mov DI, OFFSET TRANGROUP:search_best_buf
161 mov CX, fname_max_len
162 cld
163 rep movsb ; save complete pathname representation
164 cmp AL, search_com ; have we found the best of all?
165 je search_done
166
167 search_next: ; keep on looking
168 mov CX, search_attr
169 trap Find_Next ; next match
170 jnc search_loop
171
172 search_done: ; it's all over with...
173 mov AL, search_best ; pick best to return with
174 cmp ext_entered,1 ;AN005; Did user request a specific ext?
175 jz search_exit ;AN005; no - exit
176 mov al,ext_entered ;AN005; yes - get the real file type back
177 mov search_best,al ;AN005; save the real file type
178 jmp short search_exit
179
180 search_invalid_drive: ; Tell the user path/drive
181 mov DX, [search_error] ; appropriate error message
182 invoke std_printf ; and pretend no file found
183
184 search_no_file: ; couldn't find a match
185 mov AX, search_file_not_found
186
187 search_exit:
188 popf
189 pop SI
190 pop DI
191 pop DX
192 pop CX
193 ret
194 ;---------------
195 EndProc Search
196 ;----------------------------------------------------------------------------
197
198
199 break <Search_Ftype>
200 ;----------------------------------------------------------------------------
201 ; SEARCH_FTYPE determines the type of a file by examining its extension.
202 ; ENTRY:
203 ; fbuf -- dma buffer containing filename
204 ; EXIT:
205 ; AX -- file code, as given in search header
206 ; NOTE(S):
207 ; * Implicit assumption that NULL == search_file_not_found
208 ;---------------
209 ; DATA:
210 ;---------------
211 TRANDATA SEGMENT PUBLIC BYTE ;AC000;
212 extrn comext:byte,exeext:byte,batext:byte
213 trandata ends
214 ;---------------
215 Procedure Search_Ftype,NEAR
216 ;---------------
217 push DI
218 push si
219 mov AX, ANULL ; find the end of the filename
220 mov DI, OFFSET TRANGROUP:fbuf.find_buf_pname
221 mov CX, fname_max_len
222 cld
223 repnz scasb ; search for the terminating null
224 jnz ftype_exit ; weird... no null byte at end
225 sub di,5 ; . + E + X + T + NULL
226 ;
227 ; Compare .COM
228 ;
229 mov si,offset trangroup:comext
230 mov ax,di
231 cmpsw
232 jnz ftype_exe
233 cmpsw
234 jnz ftype_exe
235 mov AX, search_com ; success!
236 jmp short ftype_exit
237 ;
238 ; Compare .EXE
239 ;
240
241 ftype_exe: ; still looking... now for '.exe'
242 mov di,ax
243 mov si,offset trangroup:exeext
244 cmpsw
245 jnz ftype_bat
246 cmpsw
247 jnz ftype_bat
248 mov AX, search_exe ; success!
249 jmp short ftype_exit
250 ;
251 ; Compare .BAT
252 ;
253
254 ftype_bat: ; still looking... now for '.bat'
255 mov di,ax
256 mov si,offset trangroup:batext
257 cmpsw
258 jnz ftype_fail
259 cmpsw
260 jnz ftype_fail
261 mov AX, search_bat ; success!
262 jmp short ftype_exit
263
264 ftype_fail: ; file doesn't match what we need
265 mov ax,ANULL
266
267 ftype_exit:
268 cmp ext_entered,1 ;AN005; was an extension entered?
269 jz ftype_done ;AN005; no - exit
270 cmp ax,ANULL ;AN005; was any match found
271 jz ftype_done ;AN005; no - exit
272 mov ext_entered,al ;AN005; save the match type found
273 mov AX, search_com ;AN005; send back best was found to stop search
274
275 ftype_done: ;AN005;
276 pop SI
277 pop DI
278 ret
279
280 ;---------------
281 EndProc Search_Ftype
282 ;----------------------------------------------------------------------------
283
284
285 break <Strip>
286 ;----------------------------------------------------------------------------
287 ; STRIP copies the source string (argv[0]) into the destination buffer,
288 ; replacing any extension with wildcards.
289 ; ENTRY:
290 ; BX -- maximum length of destination buffer
291 ; DS:SI -- address of destination buffer
292 ; argv[0] -- command name to be stripped
293 ; EXIT:
294 ; CF -- set if failure, clear if successful
295 ; NOTE(S):
296 ;---------------
297 Procedure Strip,NEAR
298 ;---------------
299 push AX
300 push BX
301 push CX
302 push DX
303 push DI
304 push SI
305 pushf
306
307 mov ext_entered,1 ;AN005; assume no extension on file name
308 mov DX, DS:arg.argv[0].argpointer ; save pointer to beginning of argstring
309 mov DI, DS:arg.argv[0].argstartel ; beginning of last pathname element
310 cmp BYTE PTR [DI], 0 ; *STARTEL == NULL means no command
311 jz strip_error
312 mov CX, DX ; compute where end of argstring lies
313 add CX, DS:arg.argv[0].arglen
314 sub CX, DI ; and then find length of last element
315 inc CX ; include null as well
316 mov AL, dot ; let's find the filetype extension
317 cld
318 repnz scasb ; wind up pointing to either null or dot
319 jcxz process_ext ;AN005; if no extension found, just continue
320 mov ext_entered,0 ;AN005; we found an extension
321 mov al,ANULL ;AN005; continue scanning until the
322 repnz scasb ;AN005; end of line is reached.
323
324 process_ext: ;AN005;
325 mov CX, DI ; pointer to end of argstring yields
326 sub CX, DX ; number of bytes to be copied
327 sub BX, 4 ; can argstring fit into dest. buffer?
328 cmp CX, BX
329 jg strip_error ; if not, we must have a bad pathname
330 mov DI, SI ; destination buffer
331 mov SI, DX ; source is beginning of pathname
332 cld
333 rep movsb ; SI=arg,DI=buffer,CX=argend-argbeg
334 cmp ext_entered,1 ;AN005; if an extension was entered
335 jnz skip_wilds ;AN005; don't set up wildcard ext.
336
337 dec DI ; overwrite null or dot
338 stosb ; with a dot
339 mov AL, wildchar ; now add wildcards
340 stosb
341 stosb
342 stosb
343 mov AL, ANULL ; and a terminating null
344 stosb
345
346 skip_wilds: ;AN005;
347 popf
348 clc ; chill out...
349 jmp short strip_exit
350
351 strip_error:
352 popf
353 stc
354
355 strip_exit:
356 pop SI
357 pop DI
358 pop DX
359 pop CX
360 pop BX
361 pop AX
362 ret
363 ;---------------
364 EndProc Strip
365 ;----------------------------------------------------------------------------
366
367
368 break <Save_Args>
369 ;----------------------------------------------------------------------------
370 ; SAVE_ARGS attempts to preserve the existing argv[]/argvcnt/argbuffer
371 ; structure in newly allocated memory. The argv[] structure is found at the
372 ; beginning of this area. The caller indicates how much extra space is
373 ; needed in the resulting structure; Save_Args returns a segment number and
374 ; an offset into that area, indicating where the caller may preserve its own
375 ; data. Note that <argvcnt> can be found at <offset-2>.
376 ; ENTRY:
377 ; BX -- size (in bytes) of extra area to allocate
378 ; EXIT:
379 ; AX -- segment of new area.
380 ; CF -- set if unable to save a copy.
381 ; NOTE(S):
382 ; 1) The allocated area will be AT LEAST the size requested -- since
383 ; the underlying MSDOS call, <alloc> returns an integral number of
384 ; paragraphs.
385 ; 2) It is an error if MSDOS can't allocate AT LEAST as much memory
386 ; as the caller of Save_Args requests.
387 ; 3) AX is undefined if CF indicates an error.
388 ;---------------
389 Procedure Save_Args,NEAR
390 ;---------------
391 push BX
392 push CX
393 push DX
394 push DI
395 push SI
396 push BP
397 pushf
398 add BX, SIZE arg_unit + 0FH ; space for arg structure, round up
399 mov CL, 4 ; to paragraph size and convert
400 shr BX, CL ; size in bytes to size in paragraphs
401 trap Alloc
402 jc save_error
403 mov BP, AX ; save segment id
404 push ES ; save TRANGROUP address
405 mov ES, AX ; switch to new memory segment
406 assume ES:nothing
407 mov CX, SIZE arg_unit ; get back structure size
408 xor DI, DI ; destination is new memory area
409 mov SI, OFFSET TRANGROUP:arg ; source is arg structure
410 rep movsb ; move that sucker!
411 mov CX, arg.argvcnt ; adjust argv pointers
412 xor AX, AX ; base address for argv_calc
413 mov SI, OFFSET TRANGROUP:arg.argbuf - OFFSET arg_unit.argbuf
414
415 save_ptr_loop:
416 dec CX ; exhausted all args?
417 jl save_done
418 mov BX, CX ; get arg index and
419 invoke argv_calc ; convert to a pointer
420 mov DX, DS:arg.argv[BX].argpointer
421 sub DX, SI ; adjust argpointer
422 mov ES:argv[BX].argpointer, DX
423 mov DX, DS:arg.argv[BX].argstartel
424 sub DX, SI ; and adjust argstartel
425 mov ES:argv[BX].argstartel, DX
426 mov DX, DS:arg.argv[BX].arg_ocomptr
427 sub DX, SI ; and adjust arg_ocomptr
428 mov ES:argv[BX].arg_ocomptr, DX
429 jmp save_ptr_loop
430
431 save_done:
432 pop ES ; back we go to TRANGROUP
433 assume ES:trangroup
434 mov AX, BP ; restore segment id
435 jmp short save_ok
436
437 save_error:
438 popf
439 stc
440 jmp short save_exit
441
442 save_ok:
443 popf
444 clc
445 save_exit:
446 pop BP
447 pop SI
448 pop DI
449 pop DX
450 pop CX
451 pop BX
452 ret
453 ;---------------
454 EndProc Save_Args
455 ;----------------------------------------------------------------------------
456
457 trancode ends
458 END