When you request an open operation on a file, you are implicitly performing a search of a directory. MS-DOS examines each entry of the directory to find a match for the filename you have given as an argument; if the file is found, MS-DOS copies certain information from the directory into a data structure that it can use to control subsequent read or write operations to the file. Thus, if you wish to test for the existence of a specific file, you need only perform an open operation and observe whether it is successful. (If it is, you should, of course, perform a subsequent close operation to avoid needless expenditure of handles.)
Sometimes you may need to perform more elaborate searches of a disk directory. Perhaps you wish to find all the files with a certain extension, a file with a particular attribute, or the names of the subdirectories of a certain directory. Although the locations of a disk's directories and the specifics of the entries that are found in them are of necessity hardware dependent (for example, interpretation of the field describing the starting location of a file depends upon the physical disk format), MS-DOS does provide functions that will allow examination of a disk directory in a hardware-independent fashion.
In order to search a disk directory successfully, you must understand two types of MS-DOS search services. The first type is the "search for first" function, which accepts a file specification——possibly including wildcard characters——and looks for the first matching file in the directory of interest. If it finds a match, the function fills a buffer owned by the requesting program with information about the file; if it does not find a match, it returns an error flag.
A program can call the second type of search service, called "search for next," only after a successful "search for first." If the file specification that was originally passed to "search for first" included wildcard characters and at least one matching file was present, the program can call "search for next" as many times as necessary to find all additional matching files. Like "search for first," "search for next" returns information about the matched files in a buffer designated by the requesting program. When it can find no more matching files, "search for next" returns an error flag.
As with nearly every other operation, MS-DOS provides two parallel sets of directory-searching services:
Action FCB function Handle function
Search for first 11H 4EH
Search for next 12H 4FH
The FCB directory functions allow searches to match a filename and extension, both possibly containing wildcard characters, within the current directory for the specified or current drive. The handle directory functions, on the other hand, allow a program to perform searches within any directory on any drive, regardless of the current directory.
Searches that use normal FCBs find only normal files. Searches that use extended FCBs, or the handle-type functions, can be qualified with file attributes. The attribute bits relevant to searches are as follows:
Bit Significance
0 Read-only file
1 Hidden file
2 System file
3 Volume label
4 Directory
5 Archive needed (set when file modified)
The remaining bits of a search function's attribute parameter should be zero. When any of the preceding attribute bits are set, the search function returns all normal files plus any files with the specified attributes, except in the case of the volume-label attribute bit, which receives special treatment as described later in this chapter. Note that by setting bit 4 you can include directories in a search, exactly as though they were files.
Both the FCB and handle directory-searching functions require that the disk transfer area address be set (with Int 21H Function 1AH), before the call to "search for first," to point to a working buffer for use by MS-DOS. The DTA address should not be changed between calls to "search for first" and "search for next." When it finds a matching file, MS-DOS places the information about the file in the buffer and then inspects the buffer on the next "search for next" call, to determine where to resume the search. The format of the data returned in the buffer is different for the FCB and handle functions, so read the detailed descriptions in Section 2 of this book, "MS-DOS Functions Reference," before attempting to interpret the buffer contents.
Figures 9-2 and 9-3 provide equivalent examples of searches for all files in a given directory that have the .ASM extension, one example using the FCB directory functions (Int 21H Functions 11H and 12H) and the other using the handle functions (Int 21H Functions 4EH and 4FH). (Both programs use the handle write function with the standard output handle to display the matched filenames, to avoid introducing tangential differences in the listings.)
start: ; set DTA address for buffer
; used by search functions
mov dx,seg buff ; DS:DX = buffer address
mov ds,dx
mov dx,offset buff
mov ah,1ah ; function 1ah = search for first
int 21h ; transfer to MS-DOS
; search for first match...
mov dx,offset fcb ; DS:DX = FCB address
mov ah,11h ; function 11h = search for first
int 21h ; transfer to MS-DOS
or al,al ; any matches at all?
jnz exit ; no, quit
disp: ; go to a new line...
mov dx,offset crlf ; DS:DX = CR-LF string
mov cx,2 ; CX = string length
mov bx,1 ; BX = standard output handle
mov ah,40h ; function 40h = write
int 21h ; transfer to MS-DOS
; display matching file
mov dx,offset buff+1 ; DS:DX = filename
mov cx,11 ; CX = length
mov bx,1 ; BX = standard output handle
mov ah,40h ; function 40h = write
int 21h ; transfer to MS-DOS
; search for next match...
mov dx,offset fcb ; DS:DX = FCB address
mov ah,12h ; function 12h = search for next
int 21h ; transfer to MS-DOS
or al,al ; any more matches?
jz disp ; yes, go show filename
exit: ; final exit point
mov ax,4c00h ; function 4ch = terminate,
; return code = 0
int 21h ; transfer to MS-DOS
.
.
.
crlf db 0dh,0ah ; ASCII carriage return-
; linefeed string
fcb db 0 ; drive = current
db 8 dup ('?') ; filename = wildcard
db 'ASM' ; extension = ASM
db 25 dup (0) ; remainder of FCB = zero
buff db 64 dup (0) ; receives search results
Figure 9-2. Example of an FCB-type directory search using Int 21H Functions 11H and 12H. This routine displays the names of all files in the current directory that have the .ASM extension.
start: ; set DTA address for buffer
; used by search functions
mov dx,seg buff ; DS:DX = buffer address
mov ds,dx
mov dx,offset buff
mov ah,1ah ; function 1ah = search for first
int 21h ; transfer to MS-DOS
; search for first match...
mov dx,offset fname ; DS:DX = wildcard filename
mov cx,0 ; CX = normal file attribute
mov ah,4eh ; function 4eh = search for first
int 21h ; transfer to MS-DOS
jc exit ; quit if no matches at all
disp: ; go to a new line...
mov dx,offset crlf ; DS:DX = CR-LF string
mov cx,2 ; CX = string length
mov bx,1 ; BX = standard output handle
mov ah,40h ; function 40h = write
int 21h ; transfer to MS-DOS
; find length of filename...
mov cx,0 ; CX will be char count
; DS:SI = start of name
mov si,offset buff+30
disp1: lodsb ; get next character
or al,al ; is it null character?
jz disp2 ; yes, found end of string
inc cx ; else count characters
jmp disp1 ; and get another
disp2: ; display matching file...
; CX already contains length
; DS:DX = filename
mov dx,offset buff+30
mov bx,1 ; BX = standard output handle
mov ah,40h ; function 40h = write
int 21h ; transfer to MS-DOS
; find next matching file...
mov ah,4fh ; function 4fh = search for next
int 21h ; transfer to MS-DOS
jnc disp ; jump if another match found
exit: ; final exit point
mov ax,4c00h ; function 4ch = terminate,
; return code = 0
int 21h ; transfer to MS-DOS
.
.
.
crlf db 0dh,0ah ; ASCII carriage return-
; linefeed string
fname db '*.ASM',0 ; ASCIIZ filename to
; be matched
buff db 64 dup (0) ; receives search results
Figure 9-3. Example of a handle-type directory search using Int 21H Functions 4EH and 4FH. This routine also displays the names of all files in the current directory that have a .ASM extension.