page ,132 ;/* ; * Microsoft Confidential ; * Copyright (C) Microsoft Corporation 1991 ; * All Rights Reserved. ; */ ; SCCSID = @(#)path2.asm 1.1 85/05/14 ; SCCSID = @(#)path2.asm 1.1 85/05/14 .sall .xlist .xcref include dossym.inc include syscall.inc include find.inc include comsw.asm include comseg.asm include comequ.asm .list .cref DATARES SEGMENT PUBLIC BYTE EXTRN FORFLAG:BYTE DATARES ENDS break ;---------------------------------------------------------------------------- ; PATH.ASM contains the routines to perform pathname incovation. Path and ; Parse share a temporary buffer and argv[] definitions. , ; 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. ; assumes that the parsed command name can be found in ; argv[0] -- in other words, should be executed prior to ; . Alternatively, the command name and appropriate ; information could be placed in argv[0], or could be ; (easily) modified to make no assumptions about where its input is found. ; Please find enclosed yet another important routine, , 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: ; : argv[0]. ; : bytes to allocate in addition to arg structure ; EXIT: ; : success flag, best pathname match in EXECPATH. ; : success flag, segment address of new memory ; NOTE(S): ; * handily turns an array index into an absolute pointer. ; The computation depends on the size of an argv[] element (arg_ele). ; * calls for chunks of the command line. ; does not function as specified; see for more details. ; * 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: ;--------------- TRANSPACE SEGMENT PUBLIC BYTE ;AC000; EXTRN arg:byte EXTRN BADPMES_ptr:word EXTRN curdrv:byte EXTRN EXECPATH:byte EXTRN ext_entered:byte ;AN005; EXTRN fbuf:byte EXTRN pathinfo:word EXTRN psep_char:byte 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 ;---------------------------------------------------------------------------- ; SEARCH, when given a pathname, attempts to find a file with ; one of the following extensions: .com, .exe, .bat (highest to ; lowest priority). Where conflicts arise, the extension with ; the highest priority is favored. ; ENTRY: ; DX -- pointer to null-terminated pathname ; fbuf -- dma buffer for findfirst/next ; EXIT: ; AX -- 8) file found with .com extension ; 4) file found with .exe extension ; 2) file found with .bat extension ; 0) no such file to be found ; (if AX is non-zero:) ; [search_best] identical to AX ; [search_best_buf] null-terminated filename ; NOTES: ; 1) Requires caller to have allocated a dma buffer and executed a setdma. ;--------------- ; CONSTANTS: ;--------------- search_file_not_found equ 0 search_com equ 8 search_exe equ 4 search_bat equ 2 fname_len equ 8 fname_max_len equ 13 dot equ '.' wildchar equ '?' ;--------------- ; DATA: ;--------------- TRANSPACE SEGMENT PUBLIC BYTE ;AC000; EXTRN search_best:byte EXTRN search_best_buf:byte EXTRN search_curdir_buf:byte EXTRN search_error:word TRANSPACE ENDS ;--------------- Procedure Search,NEAR ;--------------- assume ds:trangroup, es:trangroup push CX push DX push DI push SI pushf push DX ; check drivespec (save pname ptr) mov DI, DX ; working copy of pathname mov SI, OFFSET TRANGROUP:search_curdir_buf xor DX, DX ; zero means current drive cmp BYTE PTR [DI+1],':' ; is there a drive spec? jne search_dir_check mov DL, [DI] ; get the drive byte and DL, NOT 20H ; uppercase it sub DL, '@' ; and convert to drive number search_dir_check: trap Current_Dir ; can we get the drive's current pop DX ; directory? If we can't we'll jc search_invalid_drive ; assume it's a bad drive... mov CX, search_attr ; filetypes to search for trap Find_First ; request first match, if any jc search_no_file mov search_best, search_file_not_found mov [search_best_buf], ANULL ; nothing's been found, yet search_loop: call search_ftype ; determine if .com, &c... cmp AL, search_best ; better than what we've found so far? jle search_next ; no, look for another mov search_best, AL ; found something... save its code mov SI, OFFSET TRANGROUP:fbuf.find_buf_pname mov DI, OFFSET TRANGROUP:search_best_buf mov CX, fname_max_len cld rep movsb ; save complete pathname representation cmp AL, search_com ; have we found the best of all? je search_done search_next: ; keep on looking mov CX, search_attr trap Find_Next ; next match jnc search_loop search_done: ; it's all over with... mov AL, search_best ; pick best to return with cmp ext_entered,1 ;AN005; Did user request a specific ext? jz search_exit ;AN005; no - exit mov al,ext_entered ;AN005; yes - get the real file type back mov search_best,al ;AN005; save the real file type jmp short search_exit search_invalid_drive: ; Tell the user path/drive mov DX, [search_error] ; appropriate error message invoke std_printf ; and pretend no file found search_no_file: ; couldn't find a match mov AX, search_file_not_found search_exit: popf pop SI pop DI pop DX pop CX ret ;--------------- EndProc Search ;---------------------------------------------------------------------------- break ;---------------------------------------------------------------------------- ; SEARCH_FTYPE determines the type of a file by examining its extension. ; ENTRY: ; fbuf -- dma buffer containing filename ; EXIT: ; AX -- file code, as given in search header ; NOTE(S): ; * Implicit assumption that NULL == search_file_not_found ;--------------- ; DATA: ;--------------- TRANDATA SEGMENT PUBLIC BYTE ;AC000; extrn comext:byte,exeext:byte,batext:byte trandata ends ;--------------- Procedure Search_Ftype,NEAR ;--------------- assume ds:trangroup, es:trangroup push DI push si mov AX, ANULL ; find the end of the filename mov DI, OFFSET TRANGROUP:fbuf.find_buf_pname mov CX, fname_max_len cld repnz scasb ; search for the terminating null jnz ftype_exit ; weird... no null byte at end sub di,5 ; . + E + X + T + NULL ; ; Compare .COM ; mov si,offset trangroup:comext mov ax,di cmpsw jnz ftype_exe cmpsw jnz ftype_exe mov AX, search_com ; success! jmp short ftype_exit ; ; Compare .EXE ; ftype_exe: ; still looking... now for '.exe' mov di,ax mov si,offset trangroup:exeext cmpsw jnz ftype_bat cmpsw jnz ftype_bat mov AX, search_exe ; success! jmp short ftype_exit ; ; Compare .BAT ; ftype_bat: ; still looking... now for '.bat' mov di,ax mov si,offset trangroup:batext cmpsw jnz ftype_fail cmpsw jnz ftype_fail mov AX, search_bat ; success! jmp short ftype_exit ftype_fail: ; file doesn't match what we need mov ax,ANULL ftype_exit: cmp ext_entered,1 ;AN005; was an extension entered? jz ftype_done ;AN005; no - exit cmp ax,ANULL ;AN005; was any match found jz ftype_done ;AN005; no - exit mov ext_entered,al ;AN005; save the match type found mov AX, search_com ;AN005; send back best was found to stop search ftype_done: ;AN005; pop SI pop DI ret ;--------------- EndProc Search_Ftype ;---------------------------------------------------------------------------- break ;---------------------------------------------------------------------------- ; STRIP copies the source string (argv[0]) into the destination buffer, ; replacing any extension with wildcards. ; ENTRY: ; BX -- maximum length of destination buffer ; DS:SI -- address of destination buffer ; argv[0] -- command name to be stripped ; EXIT: ; CF -- set if failure, clear if successful ; NOTE(S): ;--------------- Procedure Strip,NEAR ;--------------- assume ds:trangroup, es:trangroup push AX push BX push CX push DX push DI push SI pushf mov ext_entered,1 ;AN005; assume no extension on file name mov DX, DS:arg.argv[0].argpointer ; save pointer to beginning of argstring mov DI, DS:arg.argv[0].argstartel ; beginning of last pathname element cmp BYTE PTR [DI], 0 ; *STARTEL == NULL means no command jz strip_error mov CX, DX ; compute where end of argstring lies add CX, DS:arg.argv[0].arglen sub CX, DI ; and then find length of last element inc CX ; include null as well mov AL, dot ; let's find the filetype extension cld repnz scasb ; wind up pointing to either null or dot jcxz process_ext ;AN005; if no extension found, just continue mov ext_entered,0 ;AN005; we found an extension mov al,ANULL ;AN005; continue scanning until the repnz scasb ;AN005; end of line is reached. process_ext: ;AN005; mov CX, DI ; pointer to end of argstring yields sub CX, DX ; number of bytes to be copied sub BX, 4 ; can argstring fit into dest. buffer? cmp CX, BX jg strip_error ; if not, we must have a bad pathname mov DI, SI ; destination buffer mov SI, DX ; source is beginning of pathname cld rep movsb ; SI=arg,DI=buffer,CX=argend-argbeg cmp ext_entered,1 ;AN005; if an extension was entered jnz skip_wilds ;AN005; don't set up wildcard ext. dec DI ; overwrite null or dot stosb ; with a dot mov AL, wildchar ; now add wildcards stosb stosb stosb mov AL, ANULL ; and a terminating null stosb skip_wilds: ;AN005; popf clc ; chill out... jmp short strip_exit strip_error: popf stc strip_exit: pop SI pop DI pop DX pop CX pop BX pop AX ret ;--------------- EndProc Strip ;---------------------------------------------------------------------------- break ;---------------------------------------------------------------------------- ; SAVE_ARGS attempts to preserve the existing argv[]/argvcnt/argbuffer ; structure in newly allocated memory. The argv[] structure is found at the ; beginning of this area. The caller indicates how much extra space is ; needed in the resulting structure; Save_Args returns a segment number and ; an offset into that area, indicating where the caller may preserve its own ; data. Note that can be found at . ; ENTRY: ; BX -- size (in bytes) of extra area to allocate ; EXIT: ; AX -- segment of new area. ; CF -- set if unable to save a copy. ; NOTE(S): ; 1) The allocated area will be AT LEAST the size requested -- since ; the underlying MSDOS call, returns an integral number of ; paragraphs. ; 2) It is an error if MSDOS can't allocate AT LEAST as much memory ; as the caller of Save_Args requests. ; 3) AX is undefined if CF indicates an error. ;--------------- Procedure Save_Args,NEAR ;--------------- assume ds:trangroup, es:trangroup push BX push CX push DX push DI push SI push BP pushf add BX, SIZE arg_unit + 0FH ; space for arg structure, round up mov CL, 4 ; to paragraph size and convert shr BX, CL ; size in bytes to size in paragraphs trap Alloc jc save_error mov BP, AX ; save segment id push ES ; save TRANGROUP address mov ES, AX ; switch to new memory segment assume ES:nothing mov CX, SIZE arg_unit ; get back structure size xor DI, DI ; destination is new memory area mov SI, OFFSET TRANGROUP:arg ; source is arg structure rep movsb ; move it mov CX, arg.argvcnt ; adjust argv pointers xor AX, AX ; base address for argv_calc ; Bugbug: What did they mean by this? ; Note that the replacement line produces exactly the same code. ;; mov SI, OFFSET TRANGROUP:arg.argbuf - OFFSET arg_unit.argbuf mov SI, OFFSET TRANGROUP:arg save_ptr_loop: dec CX ; exhausted all args? jl save_done mov BX, CX ; get arg index and invoke argv_calc ; convert to a pointer mov DX, DS:arg.argv[BX].argpointer sub DX, SI ; adjust argpointer mov ES:argv[BX].argpointer, DX mov DX, DS:arg.argv[BX].argstartel sub DX, SI ; and adjust argstartel mov ES:argv[BX].argstartel, DX mov DX, DS:arg.argv[BX].arg_ocomptr sub DX, SI ; and adjust arg_ocomptr mov ES:argv[BX].arg_ocomptr, DX jmp save_ptr_loop save_done: pop ES ; back we go to TRANGROUP assume ES:trangroup mov AX, BP ; restore segment id jmp short save_ok save_error: popf stc jmp short save_exit save_ok: popf clc save_exit: pop BP pop SI pop DI pop DX pop CX pop BX ret ;--------------- EndProc Save_Args ;---------------------------------------------------------------------------- trancode ends END