Support rastport clipping rectangle for layerless rastports
[tangerine.git] / rom / dos / matchnext.c
blobc178ed883ebdaefb5e24488af7a832dffc394e5f
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc:
6 Lang: english
7 */
8 #include <exec/memory.h>
9 #include <exec/types.h>
10 #include <dos/dos.h>
11 #include <proto/exec.h>
12 #include "dos_intern.h"
13 #include <string.h>
14 #include <aros/debug.h>
16 /*****************************************************************************
18 NAME */
19 #include <dos/dosasl.h>
20 #include <proto/dos.h>
22 AROS_LH1(LONG, MatchNext,
24 /* SYNOPSIS */
25 AROS_LHA(struct AnchorPath *, AP, D1),
27 /* LOCATION */
28 struct DosLibrary *, DOSBase, 138, Dos)
30 /* FUNCTION
31 Find next file or directory that matches a given pattern.
32 See <dos/dosasl.h> for more docs and how to control MatchNext().
35 INPUTS
36 AP - pointer to Anchor Path structure which had been passed to
37 MatchFirst() before.
39 RESULT
41 NOTES
43 EXAMPLE
45 BUGS
47 SEE ALSO
48 MatchFirst() MatchEnd() CurrentDir() Examine() ExNext()
49 ParsePattern() <dos/dosasl.h>
51 INTERNALS
53 *****************************************************************************/
55 AROS_LIBFUNC_INIT
56 AROS_LIBBASE_EXT_DECL(struct DosLibrary *,DOSBase)
58 struct AChain *ac = AP->ap_Current;
59 BPTR origdir, old_current_lock;
60 LONG error = 0;
61 BOOL dir_changed = FALSE;
63 origdir = CurrentDir(0);
64 CurrentDir(origdir);
66 old_current_lock = ac->an_Lock;
68 AP->ap_Flags &= ~APF_DIDDIR;
71 ** Check if we are asked to enter a directory, but only do this
72 ** if it is really possible
75 if ((AP->ap_Flags & APF_DODIR) &&
76 (ac->an_Flags & DDF_ExaminedBit) &&
77 (ac->an_Info.fib_DirEntryType > 0) &&
78 (ac->an_Child == NULL))
81 ** Alloc a new AChain. Make it the active one. Set its string to
82 ** "#?" and mark it with DDF_AllBit Flag to indicate that this is a
83 ** "APF_DODIR-AChain". This is important for "back steppings",
84 ** because "APF_DODIR-AChains" must be removed and freed then and
85 ** the user must be notified about the leaving of a APF_DODIR-AChain
86 ** with APF_DIDDIR.
89 if ((ac->an_Child = Match_AllocAChain(1, DOSBase)))
91 ac->an_Child->an_Parent = ac;
92 ac = ac->an_Child;
93 AP->ap_Current = ac;
95 ac->an_String[0] = P_ANY;
96 ac->an_String[1] = 0;
97 ac->an_Flags = DDF_PatternBit | DDF_AllBit;
99 dir_changed = TRUE;
103 ** If the allocation did not work, we simple ignore APF_DODIR. Just
104 ** like if the user did not set this flag. Good idea or bad idea?
109 /* Main loop for AChain traversing */
111 for(;;)
113 BOOL must_go_back = FALSE;
115 /* Check for user breaks (CTRL_C, ...) */
117 if (AP->ap_BreakBits)
119 AP->ap_FoundBreak = CheckSignal(AP->ap_BreakBits);
120 if (AP->ap_FoundBreak)
122 error = ERROR_BREAK;
123 goto done;
127 /* Check if AChain must be "setup" */
129 if (!(ac->an_Flags & DDF_ExaminedBit))
132 ** This AChain must be "setup". First AChain->an_Lock must point
133 ** to the parent directory, that is the directory where this
134 ** AChain is "in". !
137 dir_changed = TRUE;
139 if (ac->an_Parent)
141 CurrentDir(ac->an_Parent->an_Lock);
142 if (ac->an_Parent->an_Flags & DDF_PatternBit)
144 ac->an_Lock = Lock(ac->an_Parent->an_Info.fib_FileName, SHARED_LOCK);
146 else
148 ac->an_Lock = Lock(ac->an_Parent->an_String, SHARED_LOCK);
151 if (!ac->an_Lock)
153 error = IoErr();
154 goto done;
157 #if !MATCHFUNCS_NO_DUPLOCK
158 else
160 ac->an_Lock = DupLock(origdir);
162 if (!ac->an_Lock)
164 error = IoErr();
165 goto done;
169 #else
171 ** If there was no ac->an_Parent then we are dealing with the
172 ** first AChain whose lock was already setup in
173 ** Match_BuildAChainList
175 #endif
177 CurrentDir(ac->an_Lock);
179 if (ac->an_Flags & DDF_PatternBit)
182 ** If this is a pattern AChain we first Examine here our
183 ** parent directory, so that it then can be traversed with
184 ** ExNext
186 if (!Examine(ac->an_Lock, &ac->an_Info))
188 error = IoErr();
189 goto done;
191 ac->an_Flags |= DDF_ExaminedBit;
193 } /* if (ac->an_Flags & DDF_PatternBit) */
194 else
196 BPTR lock;
197 LONG success;
200 ** This is a normal AChain (no pattern). Try to lock it
201 ** to see if it exists.
204 if (!(lock = Lock(ac->an_String, SHARED_LOCK)))
206 /* It does not exist, so if possible go back one step */
208 if ((AP->ap_Flags & APF_ITSWILD) && (ac->an_Parent))
210 /* [2] */
212 must_go_back = TRUE;
214 else
216 /* if going back is not possible get error code and exit */
217 error = IoErr();
218 goto done;
221 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
222 else
224 /* The File/Direcory ac->an_String exists */
226 success = Examine(lock, &ac->an_Info);
227 UnLock(lock);
229 if (!success)
232 ** Examine()ing the file/directory did not
233 ** work, although the lock was successful!?.
234 ** Get error code and exit
237 error = IoErr();
238 goto done;
242 ** This strcpy is necessary, because in case
243 ** of empty ac->an_String("") fib_FileName would
244 ** get parent directory name which it must not!
247 if (*ac->an_String == '\0')
249 strcpy(ac->an_Info.fib_FileName, ac->an_String);
252 ac->an_Flags |= DDF_ExaminedBit;
255 ** If this is a file, but there are still more path
256 ** components to follow then we have to go back one step
257 ** (AChain)
260 if (ac->an_Child && (ac->an_Info.fib_DirEntryType < 0))
262 /* [1] */
264 must_go_back = TRUE;
268 ** Here we either have found a matching file/directory
269 ** (result) or, if ac->an_Child != NULL we have still to
270 ** continue walking through the AChains until we are in
271 ** the last one. This all happens further below
274 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) else ... */
276 } /* if (ac->an_Flags & DDF_PatternBit) else ... */
278 } /* if (!(ac->an_Flags & DDF_ExaminedBit)) */
279 else
282 ** This AChain was already setup.
284 ** When an AChain which is *not* a pattern already had
285 ** DDF_PatternBit set, then this means ERROR_NO_MORE_ENTRIES, so
286 ** we try to go back one step
289 if (!(ac->an_Flags & DDF_PatternBit))
291 /* [4] */
293 must_go_back = TRUE;
298 ** Here we can be sure that the actual AChain is setup, ie: it will
299 ** have ac->an_Lock set correctly and to indicate this
300 ** DDF_ExaminedBit was set
303 CurrentDir(ac->an_Lock);
305 if (ac->an_Flags & DDF_PatternBit)
307 if(ExNext(ac->an_Lock, &ac->an_Info))
309 if (MatchPatternNoCase(ac->an_String, ac->an_Info.fib_FileName))
312 ** This file matches the pattern in ac->an_String. If
313 ** there are no more AChains to follow then we have
314 ** found a matching file/directory (a result) -->
315 ** break.
318 if (!ac->an_Child)
320 break;
322 else
324 if (ac->an_Info.fib_DirEntryType < 0)
326 /* This is a file, no chance to follow child
327 AChain. Go to top of "for(;;)" loop */
328 continue;
332 } else {
333 /* Did not match. Go to top of "for(;;)" loop */
334 continue;
337 else
339 error = IoErr();
340 if (error != ERROR_NO_MORE_ENTRIES) goto done;
342 /* [3] */
344 must_go_back = TRUE;
347 } /* if (ac->an_Flags & DDF_PatternBit) */
350 ** Handle the cases where we must (try to) go back to the previous
351 ** AChain. This can happen if the actual AChain turned out to be a
352 ** file although there are still more AChains to follow [1]. Or if
353 ** the actual AChain did not exist at all [2]. Or if in a pattern
354 ** AChain ExNext() told us that there are no more entries [3]. Or if
355 ** we were getting to a normal (no pattern) AChain which was already
356 ** setup (DDF_ExaminedBit) [4].
359 if (must_go_back)
361 /* Check if going back is possible at all */
363 if (!ac->an_Parent)
365 error = ERROR_NO_MORE_ENTRIES;
366 goto done;
369 dir_changed = TRUE;
371 /* Yep. It is possible. So let's cleanup the AChain. */
373 CurrentDir(ac->an_Parent->an_Lock);
375 UnLock(ac->an_Lock);
377 ac->an_Lock = NULL;
378 ac->an_Flags &= ~DDF_ExaminedBit;
380 /* Make ac and AP->ap_Current point to the previous AChain */
382 AP->ap_Current = ac->an_Parent;
385 ** If this was an APF_DODIR Achain (indicated by DDF_AllBit)
386 ** then the AChain must be unlinked and freed. And the user
387 ** must be informed about the leaving with APF_DIDDIR and
388 ** a "result" in AnchorPath which points to the directory which
389 ** was leaved.
392 if (ac->an_Flags & DDF_AllBit)
394 AP->ap_Current->an_Child = NULL;
395 Match_FreeAChain(ac, DOSBase);
396 AP->ap_Flags |= APF_DIDDIR;
398 /* go out of for(;;) loop --> MakeResult */
400 break;
403 ac = AP->ap_Current;
405 } /* if (must_go_back) */
406 else
408 if (!ac->an_Child)
411 ** We have reached the last AChain. And this means that
412 ** we have found a matching file/directory :-)). Go out of
413 ** for(;;) loop --> MakeResult
416 break;
419 ac = ac->an_Child;
420 AP->ap_Current = ac;
422 dir_changed = TRUE; /* CHECKME!!! Really? */
425 } /* for(;;) */
427 error = Match_MakeResult(AP, DOSBase);
429 done:
430 CurrentDir(origdir);
432 AP->ap_Flags &= ~APF_DODIR;
434 if (dir_changed)
436 AP->ap_Flags |= APF_DirChanged;
438 else
440 AP->ap_Flags &= ~APF_DirChanged;
443 SetIoErr(error);
445 return error;
447 AROS_LIBFUNC_EXIT
449 } /* MatchNext */