asm: рекурсивный поиск по диску

оригинал здесь

>===· cut recurse.asm ·===

title coded by Alexey Sangadzhiev // numlock [2:5074/11.6]
title elista, kalmykia, russia (x) 16.06.2002

model tiny
.code
.386
org 100h

;=========================================================== ============
CR = 0dh
LF = 0ah
CRLF = 0a0dh

fa_Archive = 020h
fa_AnyFile = 03fh
fa_Directory = 010h

;=========================================================== ============
SearchDir:
;-если указанный нами путь уже есть в буфере, пропускаем копирование-
cmp byte ptr [tempstr],0
jnz sd@start

;-скопируем указанный путь в наш буфер-
lea si,path
call strlen
lea di,tempstr
rep movsb

sd@start:
;-если директория не имеет конечного слэша, допишем его-
cmp byte ptr [di-1],'\'
jz addmask
mov byte ptr [di],'\'
inc di
addmask:
;-допишем маску файла + 0x00-
pusha
mov cx,maska_len
lea si,maska
rep movsb
popa

lea dx,tempstr
mov cx,fa_AnyFile
call find1st
jc find_dir

;!! здесь можно делать свои черные дела ;)
;-выведем на экран полный путь с маской-
mov al,LF
int 29h
lea si,tempstr
call print

nextfile:
;-выведем на экран имя файла-
lea si,long_name
call print
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

call findnext
jnc nextfile

call findclose

find_dir:
;-допишем маску *.* + 0x00-
mov dword ptr [di],002a2e2ah ; = '*.*',0

lea dx,tempstr
mov cx,fa_Directory
call find1st
jc sd@quit

checkattr:
;-обратываем только директории, файлы пропускаем-
cmp byte ptr [attr_dos],fa_Archive
jz @findnext
cmp byte ptr [long_name],'.'
jz @findnext

;-дописываем в конец tempstr имя директории-
lea si,long_name
call strlen
rep movsb

;-запоминаем handle и запускаем себя (рекурсия)-
push filehandle
call SearchDir
pop filehandle

;-выйдем из директории-
cmp word ptr [di],'.*'
jnz find_dir
dec di
excludedir:
dec di
cmp byte ptr [di],'\'
jnz excludedir
inc di
mov dword ptr [di],002a2e2ah ; = '*.*',0

@findnext:
call findnext
jnc checkattr

call findclose

sd@quit:
ret

;=========================================================== ============
;в SI - строка, которую нужно вывести на экран. должна оканчиваться 0x00
print:
pusha
call strlen
print@rep:
lodsb
int 29h
loop print@rep
mov al,CR
int 29h
mov al,LF
int 29h
popa
ret

;=========================================================== ============
;в CX возвращает длину строки
strlen:
push si
call strend
mov cx,si
pop si
sub cx,si
ret

;=========================================================== ============
;в SI возвращает адрес конца строки
strend:
inc si
cmp byte ptr [si-1],0
jnz strend
dec si
ret

;=========================================================== ============
;найти первый файл, подходящий по маске
;в DX - маска файла
;в CX - атрибут

Find1st:
push cx si di
xor si,si
lea di,LFNBuf
mov ax,714eh
int 21h
mov FileHandle,ax
pop di si cx
ret

FileHandle dw 0

;=========================================================== ============
;найти следующий файл, подходящий по маске
FindNext:
push bx si di
mov bx,FileHandle
xor si,si
lea di,LFNBuf
mov ax,714fh
int 21h
pop di si bx
ret

;=========================================================== ============
;закончить поиск
FindClose:
push di bx
lea di,LFNBuf
mov bx,FileHandle
mov ax,71A1h
int 21h
pop bx di
ret

;=========================================================== ============
.data
path db 'c:',0
maska db 'dmtic.log',0
maska_len = $ - maska

.data?
LFNBuf label
attr_dos dw ?
attr_win dw ?
date_create db 8 dup(?)
date_access db 8 dup(?)
date_modify db 8 dup(?)
size_h dd ?
size_high dw ?
size_low dw ?
reserve db 8 dup(?)
long_name db 260 dup(?)
short_name db 14 dup(?)

tempstr db 0ffh dup(?)
tempstrlen = $ - tempstr

;=========================================================== ============
end SearchDir
>===· cut recurse.asm ·===