全盘搜索程序
不知你编过全盘搜索程序没有,本程序用在消毒程序以及其他需要主动搜索磁盘上所有文件的地方,由于以前我自己的注释都是英文的,所以这次简单加上了一些中文。
本程序要用到的 DOS 中断很少,仅为 4EH 和 4FH,功能是查找第一个匹配文件名和继续查找,编程难点是要用到类似于堆栈的数据结构,把找到的子目录名暂时存起来,等当前目录找完后在取出来,然后继续查找下一个目录,我用的方法是开一个缓冲区,定义一个指针,用来指向缓冲区结束的地方。用的是先进先出方式,为了节省空间,每个目录项长度不等长,由每项的前 2 个字节来指向前面一条目录项。具体见源程序。
本程序要用到的 INT 21H 的 4EH 和 4FH 功能如下:
DTA 的内容如下:
源程序:
本程序要用到的 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