For those that want an easy, robust and efficient way of retrieving file and directory names and attributes, check this out:
' Searches for the first file matching the file spec `filespec` (may include
' wildcards) that has at most the file attributes specfied in `attributes`. If
' `filespec` is an empty string, then the next such file is searched for. If
' no such file exists, an empty string is returned. Otherwise, the name of the
' file found is returned, and `attributes` then contains the actual file
' attributes of the file.
'
' NOTE: Files with no attributes set are always matched. Use the returned
' value of `attributes` to filter, for instance, files with *only* the
' read-only attribute set.
declare function Dir$ ( filespec as string, attributes as integer )
' File attribute flags
const fileReadOnly% = &H01
const fileHidden% = &H02
const fileSystem% = &H04
const fileVolume% = &H08
const fileDirectory% = &H10
const fileArchive% = &H20
const fileNormal% = fileArchive or fileReadOnly or fileDirectory
const fileAny% = fileNormal or fileHidden or fileSystem or fileVolume
'' ::::: example usages
dim attributes as integer
dim filename as string
' list all of the files in the current directory that have a
' .BAS extension, and are either archives, read-only or neither:
filename = Dir( "*.bas", attributes )
do while "" <> filename
print filename
filename = Dir( "", attributes )
loop
' check to see if the file "notafile.xyz" exists:
if "" = Dir( "notafile.xyz", fileAny ) then
print "file does not exist."
end if
If there's some demand, I'll probably add the ability to retrieve time/date and size info as well. Let me know what you think, and if you have any problems with it. Here is the implementation:
function Dir$ ( filespec as string, attributes as integer )
static mcode as string * 179
static mcodeInitialized as integer
if 0 = mcodeInitialized then
mcodeInitialized = -1
mid$( mcode, 1, 4 ) = chr$( 233 )+ chr$( 48 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 5, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 9, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 13, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 17, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 21, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 25, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 29, 4 ) = chr$( 0 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 33, 4 ) = chr$( 0 )+ chr$( 49 )+ chr$( 50 )+ chr$( 51 )
mid$( mcode, 37, 4 ) = chr$( 52 )+ chr$( 53 )+ chr$( 54 )+ chr$( 55 )
mid$( mcode, 41, 4 ) = chr$( 56 )+ chr$( 46 )+ chr$( 49 )+ chr$( 50 )
mid$( mcode, 45, 4 ) = chr$( 51 )+ chr$( 0 )+ chr$( 0 )+ chr$( 0 )
mid$( mcode, 49, 4 ) = chr$( 1 )+ chr$( 2 )+ chr$( 3 )+ chr$( 85 )
mid$( mcode, 53, 4 ) = chr$( 137 )+ chr$( 229 )+ chr$( 139 )+ chr$( 94 )
mid$( mcode, 57, 4 ) = chr$( 12 )+ chr$( 138 )+ chr$( 7 )+ chr$( 60 )
mid$( mcode, 61, 4 ) = chr$( 0 )+ chr$( 116 )+ chr$( 82 )+ chr$( 139 )
mid$( mcode, 65, 4 ) = chr$( 86 )+ chr$( 6 )+ chr$( 129 )+ chr$( 194 )
mid$( mcode, 69, 4 ) = chr$( 3 )+ chr$( 0 )+ chr$( 184 )+ chr$( 0 )
mid$( mcode, 73, 4 ) = chr$( 26 )+ chr$( 205 )+ chr$( 33 )+ chr$( 139 )
mid$( mcode, 77, 4 ) = chr$( 94 )+ chr$( 10 )+ chr$( 139 )+ chr$( 15 )
mid$( mcode, 81, 4 ) = chr$( 139 )+ chr$( 94 )+ chr$( 6 )+ chr$( 129 )
mid$( mcode, 85, 4 ) = chr$( 195 )+ chr$( 46 )+ chr$( 0 )+ chr$( 137 )
mid$( mcode, 89, 4 ) = chr$( 15 )+ chr$( 139 )+ chr$( 86 )+ chr$( 12 )
mid$( mcode, 93, 4 ) = chr$( 185 )+ chr$( 255 )+ chr$( 0 )+ chr$( 184 )
mid$( mcode, 97, 4 ) = chr$( 0 )+ chr$( 78 )+ chr$( 205 )+ chr$( 33 )
mid$( mcode, 101, 4 ) = chr$( 114 )+ chr$( 75 )+ chr$( 139 )+ chr$( 94 )
mid$( mcode, 105, 4 ) = chr$( 6 )+ chr$( 129 )+ chr$( 195 )+ chr$( 24 )
mid$( mcode, 109, 4 ) = chr$( 0 )+ chr$( 138 )+ chr$( 7 )+ chr$( 180 )
mid$( mcode, 113, 4 ) = chr$( 0 )+ chr$( 60 )+ chr$( 0 )+ chr$( 116 )
mid$( mcode, 117, 4 ) = chr$( 38 )+ chr$( 139 )+ chr$( 94 )+ chr$( 6 )
mid$( mcode, 121, 4 ) = chr$( 129 )+ chr$( 195 )+ chr$( 24 )+ chr$( 0 )
mid$( mcode, 125, 4 ) = chr$( 138 )+ chr$( 7 )+ chr$( 180 )+ chr$( 0 )
mid$( mcode, 129, 4 ) = chr$( 139 )+ chr$( 94 )+ chr$( 6 )+ chr$( 129 )
mid$( mcode, 133, 4 ) = chr$( 195 )+ chr$( 46 )+ chr$( 0 )+ chr$( 139 )
mid$( mcode, 137, 4 ) = chr$( 15 )+ chr$( 33 )+ chr$( 193 )+ chr$( 129 )
mid$( mcode, 141, 4 ) = chr$( 249 )+ chr$( 0 )+ chr$( 0 )+ chr$( 117 )
mid$( mcode, 145, 4 ) = chr$( 10 )+ chr$( 184 )+ chr$( 0 )+ chr$( 79 )
mid$( mcode, 149, 4 ) = chr$( 205 )+ chr$( 33 )+ chr$( 114 )+ chr$( 25 )
mid$( mcode, 153, 4 ) = chr$( 233 )+ chr$( 203 )+ chr$( 255 )+ chr$( 139 )
mid$( mcode, 157, 4 ) = chr$( 94 )+ chr$( 10 )+ chr$( 137 )+ chr$( 7 )
mid$( mcode, 161, 4 ) = chr$( 185 )+ chr$( 13 )+ chr$( 0 )+ chr$( 139 )
mid$( mcode, 165, 4 ) = chr$( 118 )+ chr$( 6 )+ chr$( 129 )+ chr$( 198 )
mid$( mcode, 169, 4 ) = chr$( 33 )+ chr$( 0 )+ chr$( 30 )+ chr$( 7 )
mid$( mcode, 173, 4 ) = chr$( 139 )+ chr$( 126 )+ chr$( 14 )+ chr$( 243 )
mid$( mcode, 177, 4 ) = chr$( 164 )+ chr$( 93 )+ chr$( 203 )
end if
dim filespecZ as string * 128 : filespecZ = filespec + chr$( 0 )
dim isNext as integer : isNext = (0 = len( filespec ))
dim result as string * 13 : result = string$( 13, 0 )
call absolute( byval varptr( result ), byval varptr( filespecZ ), attributes, byval isNext, byval varptr( mcode ), varptr( mcode ) )
Dir$ = left$( result, instr( result, chr$( 0 ) ) - 1 )
end function
For those interested, here's the NASM source:
cpu 8086
org 0x0000
; stack:
; [bp + 14] byval result as integer ; offset of QB string char data
; [bp + 12] byval filespec as integer ; offset of ASCIIZ string
; [bp + 10] attribs as integer ; offset of the attributes var
; [bp + 8] byval isNext as integer ; zero if finding first file
; [bp + 6] byval codeoff as integer ; offset of this code
; :::::
Data: jmp Code
.DTA_reserved resb 0x15
.DTA_attribs db 0x00
.DTA_time dw 0x0000
.DTA_date dw 0x0000
.DTA_size dd 0x00000000
.DTA_filename db '12345678.123', 0
.attribs dw 0x0000
.dummy db 1, 2, 3
; :::::
Code:
push bp
mov bp, sp
mov bx, [bp + 12]
mov al, [bx]
cmp al, 0x00
je FindNext
; tell DOS to store disk transfer results in our DTA
mov dx, [bp + 6]
add dx, Data.DTA_reserved
mov ax, 0x1A00
int 0x21
; store search attributes
mov bx, [bp + 10]
mov cx, [bx]
mov bx, [bp + 6]
add bx, Data.attribs
mov [bx], cx
FindFirst:
mov dx, [bp + 12] ; ds:dx = file spec
mov cx, 0x00FF ; match any attribute combination
mov ax, 0x4E00
int 0x21
jc FileNotFound
CheckFileAttributes:
mov bx, [bp + 6]
add bx, Data.DTA_attribs
mov al, [bx]
mov ah, 0x00
cmp al, 0x00 ; no attributes ? always a match
je FileFound
;
mov bx, [bp + 6]
add bx, Data.DTA_attribs
mov al, [bx]
mov ah, 0x00
mov bx, [bp + 6]
add bx, Data.attribs
mov cx, [bx]
and cx, ax
cmp cx, 0x0000 ; any of the specified attributes ?
jne FileFound
FindNext:
mov ax, 0x4F00
int 0x21
jc FileNotFound
jmp CheckFileAttributes
FileFound:
mov bx, [bp + 10] ; return found file attributes
mov [bx], ax ; .
mov cx, 13 ; copy entire DTA name field
; (will be truncated in QB code)
mov si, [bp + 6] ; ds:si = DTA_filename
add si, Data.DTA_filename ; .
push ds ; es:di = result char data
pop es ; ...
mov di, [bp + 14] ; .
rep movsb
FileNotFound:
pop bp
retf
|