1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
|
page 80,132
title CP/DOS DosFindFirst mapper
include find.inc
FindSegment segment word public 'find'
public SearchCount
SearchCount dw 0
public ReturnBufferSave
ReturnBufferSave dd 0
public CurrentDTA
CurrentDTA dw 0
public ReturnLengthToGo
ReturnLengthToGo dw 0
public SaveDTA
SaveDTA Label dword
public SaveDTAOffset
SaveDTAOffset dw 0
public SaveDTASegment
SaveDTASegment dw 0
public SaveDTAFlag
SaveDTAFlag db 0 ; 0 -> not saved
; 1 -> is saved
; We will use the offset into the segment 'FindSegment' as the handle that we
; return and use in subsequent FindNext and FindClose calls. The data that is
; in the word is the offset into the 'FindSegment' to the DTA that we should
; use.
public FindDTAs
FindDTAs label word
rept MaxFinds
dtastr <>
endm
public FindHandles
FindHandles label word
FindDTAIndex = 0
rept MaxFinds
dw FindDTAs + FindDTAIndex
FindDTAIndex = FindDTAIndex + size dtastr
endm
FindSegment ends
dosxxx segment byte public 'dos'
assume cs:dosxxx,ds:nothing,es:nothing,ss:nothing
; ************************************************************************* *
; *
; * MODULE: DosFindFirst
; *
; * FILE NAME: DOS021.ASM
; *
; * FUNCTION: This module Finds the first filename that matches the
; * specified file specification. The directory handle
; * parameter passed will be ignored since PC/DOS does not
; * support directory handles. The last access, last write
; * and the creation date and time are all set to the same,
; * because PC/DOS does not have seperate last access and
; * last write fields in the directory. The allocation
; * fields are set equal to the eod because of the same
; * reason.
; *
; * CALLING SEQUENCE:
; *
; * PUSH@ ASCIIZ FileName ; File path name
; * PUSH@ WORD DirHandle ; Directory search handle
; * PUSH WORD Attribute ; Search attribute
; * PUSH@ OTHER ResultBuf ; Result buffer
; * PUSH DWORD ResultBufLen ; Result buffer length
; * PUSH@ WORD SearchCount ; # of entries to find
; * PUSH DWORD 0 ; Reserved (must be zero)
; * CALL DosFindFirst
; *
; * RETURN SEQUENCE:
; *
; * IF ERROR (AX not = 0)
; *
; * AX = Error Code:
; *
; * o Invalid file path name
; *
; * o Invalid search attribute
; *
; * MODULES CALLED: DOS int 21H function 2FH
; * DOS int 21H function 4EH
; * DOS int 21H function 4FH
; *
; *************************************************************************
;
public DosFindFirst
.sall
.xlist
include macros.inc
.list
str struc
old_bp dw ?
return dd ?
ReservedZero dd 0 ; reserved
FindCountPtr dd ? ; number of entries to find
FindBufferLen dw ? ; result buffer lenght
FindBufferPtr dd ? ; result buffer pointer
FileAttribute dw ? ; search attribute
DirHandlePtr dd ? ; directory search handle
PathNamePtr dd ? ; file path name pointer
str ends
DosFindFirst proc far
Enter DosFindFirst
mov ax,seg FindSegment ; get address to our data
mov ds,ax
assume ds:FindSegment
; Search for an available Find Handle
; The Dir handle that we will return is the offset into the 'FindSegment' that
; the pointer to the DTA for that handle is at. Two special things:
;
; 1) when we see file handle one, will use the first pointer and DTA
; 2) the high order bit of the DTA pointer is used to indicate that
; the handle is allocated
mov si,offset FindSegment:FindHandles
mov cx,MaxFinds
; DS:[SI] -> Find DTA Pointer Table
; CX = number of Find DTAs
; Incoming DirHandle = -1 ==> allocate a new dir handle
les di,[bp].DirHandlePtr
mov ax,es:[di]
cmp ax,-1
je AllocateHandle
; Incoming DirHandle = 1, we will use the first DTA
cmp ax,1
je HandleFound
; We have not been requested to allocate a new handle, and we are not using
; DirHandle 1. At this time, we need to reuse the incoming handle, but only
; if it is a valid (ie - previously allocated by us) DirHandle
mov si,ax ; verify it is an active handle
test ds:[si],OpenedHandle
jnz HandleFound ; jump if true
mov ax,6 ; else set error code
jmp ErrorExit ; return
; Allocate a new handle from the DTA pointer list
AllocateHandle:
add si,2
dec cx
FindHandleLoop:
test ds:[si],OpenedHandle
jz HandleFound
add si,2
loop FindHandleLoop
; No Handles available, return error
mov ax,4 ; report 'no handles available'
jmp ErrorExit ; error return - buffer not large enough
; We have a handle, let's look for the file(s)
HandleFound:
mov ax,ds:[si] ; get the dta pointer
or ds:[si],OpenedHandle ; allocate the handle
and ax,not OpenedHandle
mov CurrentDTA,ax
les di,[bp].DirHandlePtr ; the handle number we return is the
mov es:[di],si ; offset to the entry in FindSegment
; save the callers dta so we can restore it later
mov ah,02fh ; get callers DTA
int 21h
mov SaveDTAOffset,bx ; save it
mov SaveDTASegment,es
mov SaveDTAFlag,1
; Set the dta to our area
mov dx,CurrentDTA ; set DTA address
mov ah,1ah
int 21h
; Get the count of files to search for
les di,[bp].FindCountPtr ; load result buffer pointer
mov ax,es:[di] ; save the search
mov SearchCount,ax ; count
mov es:word ptr [di],0 ; set found count to zero
cmp ax,0 ; just in case they try to trick us!
jne DoSearch
jmp SearchDone
; Find first file
DoSearch:
lds dx,[bp].PathNamePtr ; load address of asciiz string
assume ds:nothing
mov cx,[bp].FileAttribute ; load the attribute
mov ax,04E00h
int 21h ; find the first occurance of file
jnc FindFirstOK ; continue
jmp ErrorExit
FindFirstOK:
mov ax,seg FindSegment
mov ds,ax
assume ds:FindSegment
mov ax,[bp].FindBufferLen ; load the buffer length
mov ReturnLengthToGo,ax ; save low order buffer length
les di,[bp].FindBufferPtr ; load result buffer pointer
mov word ptr ReturnBufferSave+0,di
mov word ptr ReturnBufferSave+2,es
; Move find data into the return areas
MoveFindData:
sub ReturnLengthToGo,size FileFindBuf ; check if result buffer is larg enough
jnc BufferLengthOk ; it is ok
mov ax,8 ; report 'Insufficient memory'
jmp ErrorExit ; error return - buffer not large enough
BufferLengthOk:
mov si,CurrentDTA ; DS:SI -> our dta area
les di,ReturnBufferSave
; At this point, the following MUST be true:
; es:di -> where we are to put the resultant data
; ds:si -> DTA from find (either first or next)
mov ax,ds:[si].DTAFileDate ; save date
mov es:[di].Create_Date,ax
mov es:[di].Access_Date,ax
mov es:[di].Write_Date,ax
mov ax,ds:[si].DTAFileTime ; save time
mov es:[di].Create_Time,ax
mov es:[di].Access_Time,ax
mov es:[di].Write_Time,ax
mov ax,ds:word ptr [si].DTAFileSize+0 ; save file size
mov es:word ptr [di].File_Size+0,ax
mov es:word ptr [di].FAlloc_Size+0,ax
mov ax,ds:word ptr [si].DTAFileSize+2
mov es:word ptr [di].File_Size+2,ax
mov es:word ptr [di].FAlloc_Size+2,ax
test es:word ptr [di].FAlloc_Size,001ffh
jz AllocateSizeSet
and es:word ptr [di].FAlloc_Size,not 001ffh
add es:word ptr [di].FAlloc_Size,00200h
AllocateSizeSet:
xor ax,ax
mov al,ds:[si].DTAFileAttrib
mov es:[di].Attributes,ax
mov cx,12
mov bx,0
MoveNameLoop:
mov al,ds:[si+bx].DTAFileName
cmp al,0
je EndOfName
mov es:[di+bx].File_Name,al
inc bx
loop MoveNameLoop
EndOfName:
mov es:[di+bx].File_Name,0
mov ax,bx
mov es:[di].String_len,al
add di,bx
mov word ptr ReturnBufferSave+0,di
mov word ptr ReturnBufferSave+2,es
les di,[bp].FindCountPtr
inc word ptr es:[di]
;
; Check if the request was for more than one
;
dec SearchCount
jz SearchDone
mov ax,04f00h ; set opcode
int 21h ; find next matching file
jc ErrorExit ; jump if error
les di,ReturnBufferSave ;
jmp MoveFindData
SearchDone:
sub ax,ax ; set good return code
ErrorExit:
push ax
mov ax,seg FindSegment
mov ds,ax
assume ds:FindSegment
cmp SaveDTAFlag,0
je DoNotRestore
mov SaveDTAFlag,0
lds dx,SaveDTA
mov ah,1ah ; load opcode
int 21h ; setup DTA
DoNotRestore:
pop ax
mexit ; pop registers
ret size str - 6 ; return
DosFindFirst endp
dosxxx ends
end
|