全盘搜索程序

不知你编过全盘搜索程序没有,本程序用在消毒程序以及其他需要主动搜索磁盘上所有文件的地方,由于以前我自己的注释都是英文的,所以这次简单加上了一些中文。
   本程序要用到的 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

posted @ 2006-06-01 10:08  ahuo  阅读(731)  评论(0编辑  收藏  举报