天天看點

全盤搜尋程式

不知你編過全盤搜尋程式沒有,本程式用在消毒程式以及其他需要主動搜尋磁盤上所有檔案的地方,由于以前我自己的注釋都是英文的,是以這次簡單加上了一些中文。

   本程式要用到的 DOS 中斷很少,僅為 4EH 和 4FH,功能是查找第一個比對檔案名和繼續查找,程式設計難點是要用到類似于堆棧的資料結構,把找到的子目錄名暫時存起來,等目前目錄找完後在取出來,然後繼續查找下一個目錄,我用的方法是開一個緩沖區,定義一個指針,用來指向緩沖區結束的地方。用的是先進先出方式,為了節省空間,每個目錄項長度不等長,由每項的前 2 個位元組來指向前面一條目錄項。具體見源程式。

   本程式要用到的 INT 21H 的 4EH 和 4FH 功能如下:

功能号 入口參數 出口參數

AH = 4EH

查找第一個比對檔案項

CX = 檔案屬性

标志 CF 複位 = 成功

找到檔案名在 DTA 内

預設 DTA 在PSP:0080H 處

DS:DX = 要查找的檔案名 ASC 字元串 标志 CF 置位 = 出錯

AH = 4FH

查找下一個比對檔案項

 

标志 CF 複位 = 成功

找到檔案名在 DTA 内

預設 DTA 在 PSP:0080H 處

标志 CF 置位 = 出錯

DTA 的内容如下:

偏移量 長度 含義
15H 位元組 找到檔案的屬性
16H

檔案時間

位11-15:小時

位5-10:分

位0-4:秒/2

18H

檔案日期

位9-15:年-1980

位8-5:月

位0-4:日

1AH 雙字 檔案大小
1EH 13位元組 ASC II 檔案名+擴充名

源程式:

;Copyright by LuoYunBin
;http://asm.yeah.net
.286p
CODE		SEGMENT
ASSUME	CS:CODE,DS:CODE
ORG	100H
START:
jmp	install
install:
call	get_com_line	;處理指令行
call	scan_disk	;全盤查找子程式
mov	ah,4ch
int	21h
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;	search the hole diskette files
;	programmed by LYB
;	include following procedures
;		scan_disk: scan disk and get all filename
;	-----------------------------------------
;	enter 	ds:si = scan drive or path name
;	return 	FIND_FILE = found file name
;		SD_ATTR	= file attribute
;	use	DO_FILE process to file operation
;	the 	data in sd_buffer is like this
;		addr1:	word -1, + path string
;		addr2:	word addr1, + path string
;		addr3:	word addr2, + path string
;		...
;		PATH_SP point to last address
SCAN_DISK	PROC	NEAR
jmp	scan_start
;	data for do_file process
SD_ATTR		DW	?		;要找的檔案屬性
FIND_FILE	DB	128 DUP (0)	;找到的檔案名
;	data use scan_disk itself
path_ep		dw	?		;目錄名緩沖區指針
path_sp		dw	path_buffer	;path buffer stack point
finding_file	db	8 dup (0)
finding_ext	db	3 dup (0)
temp_file	db	8 dup (0)
temp_ext	db	3 dup (0)
scan_start:
push	cs
pop	ds
push	cs
pop	es			;set ds,es = cs
mov	si,80h
call	phase_name		;phase file name
mov	si,path_sp
sd_lop:
inc	si
inc	si
mov	di,offset find_file
cld
call	move_byte
dec	di
cmp	byte ptr ds:[di-1],'\'	;path as N:\
jz	sd1
mov	al,'\'
stosb
sd1:
mov	path_ep,di		;path end point
mov	ax,'.*'
stosw				;add *.*
mov	al,'*'
stosb
xor	al,al
stosb
mov	ah,4eh
mov	dx,offset find_file	;找第一個檔案
mov	cx,37h			;找所有檔案屬性包括子目錄
int	21h
jb	sd_lop2_end
sd_lop2:
call	pros_dir		;處理目錄項
mov	ah,4fh			;找下一個檔案
int	21h
jnb	sd_lop2
sd_lop2_end:
mov	si,path_sp		;檢查目錄緩沖區
cmp	si,offset path_buffer	;如果還有目錄要找,則繼續
jnz	sd_new_dir
ret
sd_new_dir:
mov	di,[si]			;從緩沖區中取出新目錄
mov	path_sp,di
jmp	sd_lop
PROS_DIR	PROC
mov	si,80h			;80H 為 DTA 位址
xor	ah,ah
mov	al,ds:[si+0015h]
mov	sd_attr,ax		;找到的檔案屬性
add	si,1eh
push	si
mov	di,path_ep		;把檔案名加到路徑上
call	move_byte
pop	si
test	sd_attr,10h		;是否為子目錄
jnz	pd_is_dir
call	check_find
jnz	pd_ret
call	do_file			;對找到的檔案進行處理
;本程式的處理程式僅為列印檔案名,實際應用中,如果是用于消毒程式,可以
;在 DO_FILE 子程式中對檔案進行檢查
pd_ret:
ret
pd_is_dir:
cmp	byte ptr ds:[si],'.'	;是 . 或 .. 則忽略
jz	pd_ret
mov	di,path_sp		;如果找到新目錄
push	di			;則把它加入目錄名緩沖區
inc	di
inc	di
mov	cx,-1
xor	al,al
repnz	scasb			;find string end
pop	[di]			;fill new address
mov	path_sp,di		;point to previous address
inc	di
inc	di			;add path string
mov	si,offset find_file
call	move_byte
ret
PROS_DIR	ENDP
MOVE_BYTE	PROC
lodsb
or	al,al
jz	mb_ret
stosb
jmp	short move_byte
mb_ret:
stosb
ret
MOVE_BYTE	ENDP
;=================================================
;	check file name in DTA if match
;	the searching file name
;本子程式的作用是,如果指令行指定查找特定檔案
;則比較是否找到,如指令行輸入找 *.EXE 那麼
;就是在這兒比較
;=================================================
CHECK_FIND	PROC
mov	di,offset temp_file
mov	cx,11
xor	al,al
cld
rep	stosb
mov	si,80h+1eh
mov	di,offset temp_file
cf_lop1:
lodsb
or	al,al
jz	cf_lop2_end
cmp	al,'.'
jz	cf_lop1_end
stosb
jmp	short cf_lop1
cf_lop1_end:
mov	di,offset temp_ext
cf_lop2:
lodsb
or	al,al
jz	cf_lop2_end
stosb
jmp	short cf_lop2
cf_lop2_end:
mov	si,offset temp_file
mov	di,offset finding_file
mov	cx,11
cf_lop3:
lodsb
mov	ah,[di]
inc	di
cmp	ah,'?'
jz	cf_match	;char match
cmp	ah,al
jz	cf_match	;char match
cf_end:
ret
cf_match:
loop	cf_lop3
ret
CHECK_FIND	ENDP
;	get .ext and name and path name from com_line
;	input data in DS:SI
;	output scan file name in ES:DI
; 對要找的檔案字元串進行預處理,分離路徑和檔案名
PHASE_NAME	PROC
mov	di,offset find_file
mov	bp,di
xor	ax,ax
mov	cx,128
cld
rep	stosb
mov	di,bp
dec	bp			;bp point to find_file-1
pn_lop:
lodsb
stosb
or	al,al
jz	pn_lop_end
cmp	al,'?'
jz	pn_wild
cmp	al,'*'
jz	pn_wild
cmp	al,'\'			;path end point
jz	pn_para
cmp	al,':'
jnz	pn_lop
cmp	byte ptr [si],'\'
jz	pn_lop
mov	al,'\'
stosb
pn_para:
mov	bp,di			;save path end
dec	bp
jmp	short pn_lop
pn_wild:
mov	ah,1			;set wild char flag
jmp	short pn_lop
pn_lop_end:
or	ah,ah			;=1, then has wild char
jnz	pn_spar
mov	ah,4eh
mov	cx,37h
mov	dx,offset find_file	;check if is dir
int	21h
jb	pn_spar			;sparater path and file name
test	byte ptr ds:[80h+15h],10h
jz	pn_spar			;if not dir
mov	bp,di			;is dir
dec	bp
mov	ax,'.*'
stosw
mov	al,'*'
stosb
xor	al,al
stosb
pn_spar:
cmp	bp,offset find_file-1
jz	pn_spar1
mov	byte ptr ds:[bp],0
mov	si,offset find_file
mov	di,offset path_buffer+2
call	move_byte
pn_spar1:
inc	bp
mov	si,bp
mov	di,offset finding_file
mov	cx,8
pn_lop1:
lodsb				;get filename
cmp	al,'.'
jz	pn_lop2_1
or	al,al
jz	pn_lop3_end
cmp	al,'*'
jz	pn_lop1_store
stosb
loop	pn_lop1
jmp	short pn_lop2
pn_lop1_store:
mov	al,'?'
rep	stosb
pn_lop2:
lodsb
pn_lop2_1:
or	al,al
jz	pn_lop3_end
cmp	al,'.'
jnz	pn_lop2
mov	di,offset finding_ext
mov	cx,3
pn_lop3:
lodsb				;get ext name
or	al,al
jz	pn_lop3_end
cmp	al,'*'
jz	pn_lop3_store
stosb
loop	pn_lop3
jmp	short pn_lop3_end
pn_lop3_store:
mov	al,'?'
rep	stosb
pn_lop3_end:
mov	al,'?'
cmp	finding_file,0
jnz	pn1
mov	di,offset finding_file
mov	cx,8
rep	stosb
pn1:
cmp	finding_ext,0
jnz	pn2
mov	di,offset finding_ext
mov	cx,3
rep	stosb
pn2:
ret
PHASE_NAME	ENDP
SCAN_DISK	ENDP
do_file		proc
mov	si,offset d_searching
call	printf
ret
do_file		endp
d_searching	db	'Searching file: %c%79t',0dh,0
dw	find_file
GET_COM_LINE	PROC
;	get command line file name
;	to CL_FILE and return CY when no command line
;	return NC when has command line
;	the sub change lower letter to upper letter
; 指令行處理子程式
mov	si,81h
mov	di,80h
cld
cmd_lop:
lodsb
cmp	al,0dh
jz	cmd_lop_end
cmp	al,' '
jbe	cmd_lop	;如果是小寫字母
cmp	al,'a'		;則轉換到大寫
jb	stos_it	;因為大小寫字母 ASC 碼值剛好差 20H
cmp	al,'z'	;是以把 ASC 碼減 20H 就換到大寫了
ja	stos_it
sub	al,20h		;convert to upper case
stos_it:
stosb
jmp	short cmd_lop
cmd_lop_end:
xor	al,al
stosb
ret
GET_COM_LINE	ENDP
include		printf.asm	;一個公用的顯示程式
FILE_END	EQU	THIS BYTE
path_buffer	db	1000h dup (0)	;path buffer
CODE		ENDS
END	START
      

繼續閱讀