added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / rom / dos / exall.c
blob70066e34c8b156e851d7c9c69311615ac5599969
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Examine a directory.
6 Lang: English
7 */
8 #include <exec/memory.h>
9 #include <proto/exec.h>
10 #include <dos/filesystem.h>
11 #include <dos/exall.h>
12 #include <stddef.h>
13 #include "dos_intern.h"
14 #include <aros/asmcall.h>
15 #include <aros/debug.h>
17 /*****************************************************************************
19 NAME */
20 #include <proto/dos.h>
22 AROS_LH5(BOOL, ExAll,
24 /* SYNOPSIS */
25 AROS_LHA(BPTR, lock, D1),
26 AROS_LHA(struct ExAllData *, buffer, D2),
27 AROS_LHA(LONG, size, D3),
28 AROS_LHA(LONG, data, D4),
29 AROS_LHA(struct ExAllControl *, control, D5),
31 /* LOCATION */
32 struct DosLibrary *, DOSBase, 72, Dos)
34 /* FUNCTION
36 Examine an entire directory.
38 INPUTS
40 lock -- lock on the directory to be examined
41 buffer -- buffer for the data that is returned (must be aligned)
42 which is filled with (partial) ExAllData structures
43 (see NOTES)
44 size -- size of 'buffer' in bytes
45 type -- type of the data to be returned
46 control -- a control structure allocated by AllocDosObject()
48 RESULT
50 An indicator of if ExAll() is done. If FALSE is returned, either ExAll()
51 has completed in which case IoErr() is ERROR_NO_MORE_ENTRIES or an
52 error occurred. If a non-zero value is returned ExAll() must be called
53 again until it returns FALSE.
55 NOTES
57 The following information is essential information on the ExAllData
58 structure:
60 ead_type :
62 ED_NAME -- filename
63 ED_TYPE -- type
64 ED_SIZE -- size in bytes
65 ED_PROTECTION -- protection bits
66 ED_DATE -- date information (3 longwords)
67 ED_COMMENT -- file comment (NULL if no comment exists)
68 ED_OWNER -- owner user and group id
70 This is an incremental list meaning that if you specify ED_OWNER you
71 will get ALL attributes!
74 Filesystems that support ExAll() must support at least up to ED_COMMENT.
75 If a filesystem doesn't support a particular type, ERROR_BAD_NUMBER must
76 be returned.
78 ead_Next : pointer to the next entry in the buffer. The last entry
79 has a NULL value for ead_Next.
82 The control structure have the following fields.
84 eac_Entries : the number of entries in the buffer after a call to ExAll().
85 Make sure that your code handles the case when eac_Entries
86 is 0 and ExAll() returns TRUE.
88 eac_LastKey : must be initialized to 0 before calling ExAll() for the
89 first time.
91 eac_MatchString : if NULL then information on all files will be returned.
92 If non-NULL it's interpreted as a pointer to a string
93 used for pattern matching which files to return
94 information on. This string must have been parsed by
95 ParsePatternNoCase()!
97 eac_MatchFunc : pointer to a hook that will be called to decide if an
98 entry should be included in the buffer. If NULL, no
99 matching function will be called. The hook is called as
100 follows
102 BOOL = MatchFunc(hook, data, typeptr)
104 EXAMPLE
106 BUGS
108 SEE ALSO
110 Examine(), ExNext(), MatchPatternNoCase(), ParsePatternNoCase(),
111 AllocDosObject(), ExAllEnd()
113 INTERNALS
115 *****************************************************************************/
117 AROS_LIBFUNC_INIT
119 /* Get pointer to filehandle */
120 struct FileHandle *fh = (struct FileHandle *)BADDR(lock);
122 /* Get pointer to I/O request. Use stackspace for now. */
123 struct IOFileSys iofs;
125 /* If fib != NULL it means we've already been called and found out that
126 we needed to emulate ExAll, thus don't waste time sending messages to the
127 handler. */
128 if (((struct InternalExAllControl *)control)->fib != NULL ||
129 control->eac_MatchString || control->eac_MatchFunc)
131 #warning "Hack because of problem with our filesystem API regarding"
132 #warning "ExAll handling. Filesystems don't get passed matchstring/matchfunc"
133 #warning "so they cannot handle it. As workaround for now we force emulation"
134 #warning "of ExAll() if any of matchstring/matchfunc is set."
135 #warning "It would be better to pass ExAllControl structure to filesystems."
136 #warning "Ie. change filesystem API. Also because of eac_LastKey!!!"
138 iofs.io_DosError = ERROR_ACTION_NOT_KNOWN;
140 else
142 /* Prepare I/O request. */
143 InitIOFS(&iofs, FSA_EXAMINE_ALL, DOSBase);
145 iofs.IOFS.io_Device = fh->fh_Device;
146 iofs.IOFS.io_Unit = fh->fh_Unit;
148 iofs.io_Union.io_EXAMINE_ALL.io_ead = buffer;
149 iofs.io_Union.io_EXAMINE_ALL.io_eac = control;
150 iofs.io_Union.io_EXAMINE_ALL.io_Size = size;
151 iofs.io_Union.io_EXAMINE_ALL.io_Mode = data;
153 /* Send the request. */
154 DosDoIO(&iofs.IOFS);
159 iofs.io_DosError == ERROR_NOT_IMPLEMENTED ||
160 iofs.io_DosError == ERROR_ACTION_NOT_KNOWN
163 /* Try to emulate it */
164 STRPTR end = (STRPTR)buffer + size;
165 STRPTR next;
167 struct ExAllData *last = buffer, *curr = buffer;
169 struct InternalExAllControl *icontrol = (struct InternalExAllControl *)control;
171 static const ULONG sizes[]=
174 offsetof(struct ExAllData,ed_Type),
175 offsetof(struct ExAllData,ed_Size),
176 offsetof(struct ExAllData,ed_Prot),
177 offsetof(struct ExAllData,ed_Days),
178 offsetof(struct ExAllData,ed_Comment),
179 offsetof(struct ExAllData,ed_OwnerUID),
180 sizeof(struct ExAllData)
183 /* No errors for now. */
184 iofs.io_DosError = 0;
186 /* Allocate the FIB structure, if not allocated yet. It will be deallocated
187 by DeleteDosObject(). */
188 if (!icontrol->fib)
190 icontrol->fib = AllocDosObject(DOS_FIB, NULL);
191 if (!icontrol->fib)
193 iofs.io_DosError == IoErr();
194 goto end;
198 /* No entries found as of now yet. */
199 control->eac_Entries = 0;
201 /* If LastKey == 0 it means this is the first time we're getting called,
202 in which case we need to initialize the FIB structure and a few other things.
203 A "nice" side effect of this, is that if one wants to restart the scanning,
204 he/she just has to set LastKey to 0. */
205 if (control->eac_LastKey == 0)
207 if (!Examine(lock, icontrol->fib))
209 iofs.io_DosError == IoErr();
210 goto end;
212 if (icontrol->fib->fib_DirEntryType <= 0)
214 iofs.io_DosError = ERROR_OBJECT_WRONG_TYPE;
215 goto end;
219 /* Macro used when the data doesn't fit in the provided buffer.
220 In case not even one element fit in the buffer, return a buffer
221 overflow error, so that the user knows he/she has to increase the
222 buffer. */
223 #define ReturnOverflow() \
224 do { \
225 if (last == curr) \
226 iofs.io_DosError = ERROR_BUFFER_OVERFLOW; \
228 icontrol->fib->fib_DiskKey = control->eac_LastKey; \
229 goto end; \
230 } while (0)
232 /* Copy a string pointer by _source into the buffer provided
233 to the ExAll function. This macro gracefully handles buffer
234 overflows. */
235 #define CopyStringSafe(_source) \
236 do { \
237 STRPTR source = _source; \
239 for (;;) \
241 if (next >= end) \
242 ReturnOverflow(); \
243 if (!(*next++ = *source++)) \
244 break; \
246 } while (0)
249 if (data > ED_OWNER)
250 /* We don't have that many fields to fill in... */
251 iofs.io_DosError = ERROR_BAD_NUMBER;
252 else
256 ExNext(lock, icontrol->fib);
257 /* Record the latest DiskKey into LastKey so that we can roll back to it
258 in case of a buffer overflow and when getting called again. */
259 control->eac_LastKey = icontrol->fib->fib_DiskKey
262 /* Try to match the filename, if required. */
263 if (control->eac_MatchString &&
264 !MatchPatternNoCase(control->eac_MatchString,
265 icontrol->fib->fib_FileName))
266 continue;
268 next = (STRPTR)curr + sizes[data];
270 /* Oops, the buffer is full. */
271 if (next > end)
272 ReturnOverflow();
274 /* Switch over the requested fields and fill them as appropriate. */
275 switch(data)
277 case ED_OWNER:
278 curr->ed_OwnerUID = icontrol->fib->fib_OwnerUID;
279 curr->ed_OwnerGID = icontrol->fib->fib_OwnerGID;
281 /* Fall through */
282 case ED_COMMENT:
283 curr->ed_Comment = next;
284 CopyStringSafe(icontrol->fib->fib_Comment);
286 /* Fall through */
287 case ED_DATE:
288 curr->ed_Days = icontrol->fib->fib_Date.ds_Days;
289 curr->ed_Mins = icontrol->fib->fib_Date.ds_Minute;
290 curr->ed_Ticks = icontrol->fib->fib_Date.ds_Tick;
292 /* Fall through */
293 case ED_PROTECTION:
294 curr->ed_Prot = icontrol->fib->fib_Protection;
296 /* Fall through */
297 case ED_SIZE:
298 curr->ed_Size = icontrol->fib->fib_Size;
300 /* Fall through */
301 case ED_TYPE:
302 curr->ed_Type = icontrol->fib->fib_DirEntryType;
304 /* Fall through */
305 case ED_NAME:
306 curr->ed_Name = next;
307 CopyStringSafe(icontrol->fib->fib_FileName);
309 /* Fall through */
310 case 0:
311 curr->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
314 /* Do some more matching... */
315 if (control->eac_MatchFunc &&
316 !AROS_UFC3(LONG, control->eac_MatchFunc,
317 AROS_UFCA(struct Hook *, control->eac_MatchFunc, A0),
318 AROS_UFCA(struct ExAllData *, curr, A2),
319 AROS_UFCA(LONG *, &data, A1)))
320 continue;
322 /* Finally go to the next entry in the buffer. */
323 last = curr;
324 curr = curr->ed_Next;
325 control->eac_Entries++;
327 iofs.io_DosError = IoErr();
329 end:
330 /* This is the last one, after it there's nothing. */
331 last->ed_Next = NULL;
334 /* Set error code and return */
335 SetIoErr(iofs.io_DosError);
336 return (iofs.io_DosError == 0) ? DOSTRUE : DOSFALSE;
338 AROS_LIBFUNC_EXIT
339 } /* ExAll */