diff options
Diffstat (limited to 'v4.0/src/CMD/COMMAND/PATH2.ASM')
| -rw-r--r-- | v4.0/src/CMD/COMMAND/PATH2.ASM | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/v4.0/src/CMD/COMMAND/PATH2.ASM b/v4.0/src/CMD/COMMAND/PATH2.ASM new file mode 100644 index 0000000..8f8d8b8 --- /dev/null +++ b/v4.0/src/CMD/COMMAND/PATH2.ASM | |||
| @@ -0,0 +1,458 @@ | |||
| 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 | ||