📄 ifindfil.asm
字号:
; FILENAME: IFINDFIL.ASM
;
; Copyright (c) 1988, 1992 by Borland International, Inc.
;
; DESCRIPTION: This module implement a routine that performs a recursive
; search through a hard disk of a specified file.
;
; ASSEMBLY INSTRUCTIONS: To assemble this module use the following
; TASM command line.
;
; TASM /dMDL=memorymodel ifindfil
;
; 'memorymodel' in the above command line may be replaced by TINY, SMALL,
; MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
; a 286/386 machine, turn on the P286 directive in order to take advantage of
; 286/386 specific instructions. For example:
;
; TASM /dMDL=memorymodel /jP286 ifindfil
jumps
%tabsize 4
ifndef MDL
display "Error: This module requires that you provide a memory model"
display " definition on the command line. I.E. /dMDL=SMALL."
err ; Force a fatal error
else
ideal ; Use TASM's Ideal mode
% model MDL,pascal ; Define the memory model
include "iwhglobl.inc"
include "imacros.mac"
include "idos.inc"
include "dos.inc"
include "idos.mac"
include "kbd.inc"
include "bios.inc"
include "ibios.mac"
global BreakPressed:byte ; Check this often for a nonzero
; value. Terminate if a nonzero
; value is found.
dataseg
AllFiles db "*.*",0 ; ASCIIZ string representing all files
SwitchChar db 1,'\' ; Directory seperating character
CurrentDir db MAX_PATH_LENGTH dup (0)
MakePascalString BlankLine, <13, 10>
; The following variable keep track of going through the
; file specifications that were given on the command line.
FileSpecIndex db ?
FileSpecPtr dw ?
codeseg
macro NewLine ; Force a new line
;; ifdef _286_
;; push seg BlankLine
;; push offset BlankLine
;; else
;; mov ax, seg BlankLine
;; push ax
;; mov ax, offset BlankLine
;; push ax
;; endif
call WritePascalString,seg BlankLine,offset BlankLine
endm
TerminateKeyMssg db 13,10
db '**ERROR** Whereis terminated due to keypress.'
db 13,10,0
; The following messages should not include a line feed.
PauseKeyMssg db 'Press space to continue....',13,0
PauseKeyEraseMssg db ' ',13,0
proc FindFiles
; This routine does a recursive search down through the directory
; structure of a disk looking for a file. If the routine finds a
; match it displays the complete drive\path\filename. The routine
; uses the following algorithm:
;
; make room for a local copy of the Dta
; change directories to the location of the file we're looking for
; find all matches in the current directory
; for each sub-directory in the current directory
; Do a recursive call to this routine
; restore the original directory
;
; The routine uses the global variable FileSpec as the specification
; of the file to search for.
; If any key is pressed, a message is printed and then this routine
; calls Terminate.
;
; Input
; DS - points to the segment in which FileSpec resides
; Path - A pascal style string representing the path in which to
; search for the file
; Output
; none
; Calling convention
; Pascal
; Registers modified
; ax, bx, cx, dx, si, es, flags
arg Path:byte:MAX_PATH_LENGTH=PARM_SIZE
local DataTransferArea:byte:DTA_SIZE=LOCAL_SIZE ;
; The PASCAL calling convention on the MODEL statement causes TASM
; to do the following automatically.
; push bp
; mov bp, sp
; ; make room for the Dta, Drive, Path and Filename on the stack
; sub sp, LOCAL_SIZE
mov [FileSpecIndex],1 ; Keep track which one we are searching
mov [FileSpecPtr],offset FileSpec
mov si, bp ; Get the address of the Dta buffer
sub si, DTA_SIZE
push ds ; Store ds before call to SetDTA
SetDTA <ss>, <si> ; Set the current Dta address
pop ds ; Restore ds after SetDTA
if @CodeSize eq 0 ; FindFiles is near
add si, DTA_SIZE + 5 ; Get the address of the Path
else
add si, DTA_SIZE + 7 ; Get the address of the Path
endif
xor bx, bx
mov bl, [byte ss:si-1] ; Get the length byte
cmp bl, 1 ; Check if the path is 1 letter. If it
jle ChangeDirs ; is we don't want to remove it.
cmp [byte ss:si+bx-1], '\' ; Check if the path ends with a '\'. If
jne ChangeDirs ; it does, remove it.
mov [byte ss:si+bx-1], 0
dec [byte ss:si-1]
ChangeDirs:
push ds
ChangeDirectory <ss>, <si> ; Change the directory
GetCurrentDir <0>, <seg CurrentDir>, <offset CurrentDir>
pop ds
if (@Cpu and 100b) eq 100b
push seg CurrentDir
push offset CurrentDir
else
mov ax, seg CurrentDir
push ax
mov ax, offset CurrentDir
push ax
endif
mov ax, 0020h ; Replace spaces with 0
mov cx, MAX_PATH_LENGTH
call FindAndReplace
FirstFile:
mov ax,[FileSpecPtr]
inc ax ; Get past length byte
FindFirst <0FFh>, <ds>, <ax>
NextFile: ; Find each of the matching files
cmp ax, 0
jne CheckNextFileSpec
; Check if the user has pressed a key to interrupt WHEREIS.
GetKbdStatus
jz NoKey
call KeyWasPressed
; Come here to print a matching file.
NoKey:
if (@Cpu and 100b) eq 100b
push seg Drive ; Get the address of the drive
push offset Drive ; description
else
mov ax, seg Drive
push ax
mov ax, offset Drive
push ax
endif
mov al, [Drive]
xor ah, ah
call WritePascalString ; Display the drive description
mov ax, seg CurrentDir
mov es, ax
mov di, offset CurrentDir
cmp [byte es:di], 'A' ; Check if the string is empty
jl DontNeedBackSlash
dec di ; Decrement the offset of the pointer
DontNeedBackSlash:
push es
push di
call WriteASCIIZString
if (@Cpu and 100b) eq 100b
push seg SwitchChar
push offset SwitchChar
else
mov ax, seg SwitchChar
push ax
mov ax, offset SwitchChar
push ax
endif
call WritePascalString
mov si, bp
sub si, DTA_SIZE - (offset (Dta).Filename)
push ss si ; Push an extra copy of offset of filename
; Write the filename. Pass the address of the filename
call WriteASCIIZString,ss,si
NewLine
pop si ax ; Offset of filename ax:si
mov di,offset CurrentDir
push ds ; Store ds before call to
; ExecuteDosCommand and SetDTA
call ExecuteDosCommand ; Do the command for the file.
mov si, bp ; Get the address of the Dta buffer
sub si, DTA_SIZE
SetDTA <ss>, <si> ; Set the current Dta address
pop ds ; Restore ds after SetDTA
FindNext
jmp NextFile
CheckNextFileSpec:
cmp [BreakPressed],0 ; Check for CTRL-BREAK
jnz GiveAbortMessage
add [FileSpecPtr],FILE_SPEC_SIZE ; Point to next filespec
mov al,[FileSpecIndex] ; Bump up counter
inc al
mov [FileSpecIndex],al
cmp al,[FileSpecCounter]
jle FirstFile ; Go back to search another filespec
CheckDirectories:
push ds
FindFirst <010000b>, <(seg AllFiles)>, <(offset AllFiles)>
pop ds
NextDirectory:
cmp ax, 0 ; Check if we've found a sub-directory
je CheckAttributes
jmp Exit
CheckAttributes: ; Check if it's a directory
mov si, bp ; Get the address of the attribute
sub si, DTA_SIZE - (offset (Dta).FileAttribute)
mov al, [byte ss:si] ; Get the directory entries attributes
and al, 10000b
cmp al, 10000b
jne GetNextDirectory
; Check if the directory is '.' or '..'
mov si, bp ; Get the address of the attribute
sub si, DTA_SIZE - (offset (Dta).Filename)
cmp [byte ss:si], '.' ; If it's '.' or '..' then skip
je GetNextDirectory ; it
; Copy the new path onto the stack
sub sp, MAX_PATH_LENGTH ; Make room on the stack
mov bx, sp
push ss ; Push segment address of Path
mov si, bp
if @CodeSize eq 0 ; FindFiles is near
add si, 4 ; get offset of current path string
else
add si, 6
endif
push si ; Push offset of path
push ss ; Push address to copy to
push bx
mov al, [byte Path] ; Get the path length
inc al ; Copy the length byte also
call ByteCopy ; Copy the path onto the stack
; Append the new directory to the path on the stack
push es di ; Save es:di before call to
; GetASCIIZStrLen
mov si, bp ; Get the address of the current Dta
; Get the address of the directory name from it's location in the Dta
sub si, DTA_SIZE - (offset (Dta).Filename)
call GetASCIIZStrLen,ss,si ; Get the length of the directory name
pop di es ; Restore es:di
cmp [byte es:di-1], '\' ; Check if the path on the stack ends
je HasBackSlash ; with a '\'. If not append one.
mov [byte es:di], '\'
inc di
push si
mov si, sp ; Adjust the length byte of the string
inc [byte ss:si+2]
pop si
HasBackSlash:
; Copy the directory name
call ByteCopy,ss,si, \ ; Address of the directory name.
es,di ; Address to copy directory name to
mov si, sp ; Adjust the length byte of the string
dec al ; we appended to. Don't include the
add [byte ss:si], al ; terminating 0 in the length
; Do recursive call
call FindFiles ; Do the search for the file(s)
push ds
mov ax, bp
if @CodeSize eq 0 ; Near code models
add ax, 5
else
add ax, 7
endif
ChangeDirectory <ss>, <ax> ; Change to the directory that was
pop ds ; active before the recursive call
;; Remember, the following cleanup is done automatically by Pascal Model.
;; add sp, MAX_PATH_LENGTH ; Remove space allocated on the stack
mov si, bp
sub si, DTA_SIZE
push ds
SetDTA <ss>, <si> ; Restore the Dta
pop ds
GetNextDirectory:
FindNext ; Find the next sub-directory
jmp NextDirectory
Exit:
; Once again, the cleanup is done automatically because of PASCAL model.
; add sp, LOCAL_SIZE
; pop bp
ret
endp FindFiles
proc KeyWasPressed
; This routine handles pausing if a space or ^S was pressed,
; or terminating WHEREIS if any other key was pressed.
; Throw out the key(s) that were pressed.
DiscardKeys:
GetChar
cmp al,' ' ; Check for space pressed to pause
je JustPausing
cmp al,'s'-'a'+1 ; Check for ^S pressed to pause
je JustPausing
FlushKeyboard:
GetKbdStatus
jz GiveAbortMessage
GetChar
jmp FlushKeyboard
GiveAbortMessage:
; Give a message to the user that WHEREIS is terminating.
call WriteASCIIZString,seg TerminateKeyMssg,offset TerminateKeyMssg
call Terminate
JustPausing:
; Give a message to the user that WHEREIS is pausing
call WriteASCIIZString,seg PauseKeyMssg,offset PauseKeyMssg
WaitForSpace:
GetKbdStatus
jz WaitForSpace
GetChar
cmp al,' '
jne FlushKeyboard
; Now get rid of the reminder
call WriteASCIIZString,seg PauseKeyEraseMssg,offset PauseKeyEraseMssg
ret
endp KeyWasPressed
endif ; ifndef MDL
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -