start service tasks separately in-case platforms need to perform additional set-up...
[AROS.git] / rom / dos / matchnext.c
blob66c5162b81d26d5f2322e283c9988297f70f8403
1 /*
2 Copyright © 1995-2013, 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().
34 INPUTS
35 AP - pointer to Anchor Path structure which had been passed to
36 MatchFirst() before.
38 RESULT
39 Zero on success, or error code on failure.
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
57 struct AChain *ac = AP->ap_Current;
58 BPTR origdir;
59 LONG error = 0;
60 BOOL dir_changed = FALSE;
62 origdir = CurrentDir(0);
63 CurrentDir(origdir);
65 AP->ap_Flags &= ~APF_DIDDIR;
68 ** Check if we are asked to enter a directory, but only do this
69 ** if it is really possible
72 if ((AP->ap_Flags & APF_DODIR) &&
73 (ac->an_Flags & DDF_ExaminedBit) &&
74 (ac->an_Info.fib_DirEntryType > 0) &&
75 (ac->an_Child == NULL))
78 ** Alloc a new AChain. Make it the active one. Set its string to
79 ** "#?" and mark it with DDF_AllBit Flag to indicate that this is a
80 ** "APF_DODIR-AChain". This is important for "back steppings",
81 ** because "APF_DODIR-AChains" must be removed and freed then and
82 ** the user must be notified about the leaving of a APF_DODIR-AChain
83 ** with APF_DIDDIR.
86 if ((ac->an_Child = Match_AllocAChain(1, DOSBase)))
88 ac->an_Child->an_Parent = ac;
89 ac = ac->an_Child;
90 AP->ap_Current = ac;
92 ac->an_String[0] = P_ANY;
93 ac->an_String[1] = 0;
94 ac->an_Flags = DDF_PatternBit | DDF_AllBit;
96 dir_changed = TRUE;
100 ** If the allocation did not work, we simple ignore APF_DODIR. Just
101 ** like if the user did not set this flag. Good idea or bad idea?
106 /* Main loop for AChain traversing */
108 for(;;)
110 BOOL must_go_back = FALSE;
112 /* Check for user breaks (CTRL_C, ...) */
114 if (AP->ap_BreakBits)
116 AP->ap_FoundBreak = CheckSignal(AP->ap_BreakBits);
117 if (AP->ap_FoundBreak)
119 error = ERROR_BREAK;
120 goto done;
124 /* Check if AChain must be "setup" */
126 if (!(ac->an_Flags & DDF_ExaminedBit))
129 ** This AChain must be "setup". First AChain->an_Lock must point
130 ** to the parent directory, that is the directory where this
131 ** AChain is "in". !
134 dir_changed = TRUE;
136 if (ac->an_Parent)
138 CurrentDir(ac->an_Parent->an_Lock);
139 if (ac->an_Parent->an_Flags & DDF_PatternBit)
141 ac->an_Lock = Lock(ac->an_Parent->an_Info.fib_FileName, SHARED_LOCK);
143 else
145 ac->an_Lock = Lock(ac->an_Parent->an_String, SHARED_LOCK);
148 if (!ac->an_Lock)
150 error = IoErr();
151 goto done;
154 #if !MATCHFUNCS_NO_DUPLOCK
155 else
157 ac->an_Lock = DupLock(origdir);
159 if (!ac->an_Lock)
161 error = IoErr();
162 goto done;
166 #else
168 ** If there was no ac->an_Parent then we are dealing with the
169 ** first AChain whose lock was already setup in
170 ** Match_BuildAChainList
172 #endif
174 CurrentDir(ac->an_Lock);
176 if (ac->an_Flags & DDF_PatternBit)
179 ** If this is a pattern AChain we first Examine here our
180 ** parent directory, so that it then can be traversed with
181 ** ExNext
183 if (!Examine(ac->an_Lock, &ac->an_Info))
185 error = IoErr();
186 goto done;
188 ac->an_Flags |= DDF_ExaminedBit;
190 } /* if (ac->an_Flags & DDF_PatternBit) */
191 else
193 BPTR lock;
194 LONG success;
197 ** This is a normal AChain (no pattern). Try to lock it
198 ** to see if it exists.
201 if (!(lock = Lock(ac->an_String, SHARED_LOCK)))
203 /* It does not exist, so if possible go back one step */
205 if ((AP->ap_Flags & APF_ITSWILD) && (ac->an_Parent))
207 /* [2] */
209 must_go_back = TRUE;
211 else
213 /* if going back is not possible get error code and exit */
214 error = IoErr();
215 goto done;
218 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
219 else
221 /* The File/Direcory ac->an_String exists */
223 success = Examine(lock, &ac->an_Info);
224 UnLock(lock);
226 if (!success)
229 ** Examine()ing the file/directory did not
230 ** work, although the lock was successful!?.
231 ** Get error code and exit
234 error = IoErr();
235 goto done;
239 ** This strcpy is necessary, because in case
240 ** of empty ac->an_String("") fib_FileName would
241 ** get parent directory name which it must not!
244 if (*ac->an_String == '\0')
246 strcpy(ac->an_Info.fib_FileName, ac->an_String);
249 ac->an_Flags |= DDF_ExaminedBit;
252 ** If this is a file, but there are still more path
253 ** components to follow then we have to go back one step
254 ** (AChain)
257 if (ac->an_Child && (ac->an_Info.fib_DirEntryType < 0))
259 /* [1] */
261 must_go_back = TRUE;
265 ** Here we either have found a matching file/directory
266 ** (result) or, if ac->an_Child != NULL we have still to
267 ** continue walking through the AChains until we are in
268 ** the last one. This all happens further below
271 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) else ... */
273 } /* if (ac->an_Flags & DDF_PatternBit) else ... */
275 } /* if (!(ac->an_Flags & DDF_ExaminedBit)) */
276 else
279 ** This AChain was already setup.
281 ** When an AChain which is *not* a pattern already had
282 ** DDF_PatternBit set, then this means ERROR_NO_MORE_ENTRIES, so
283 ** we try to go back one step
286 if (!(ac->an_Flags & DDF_PatternBit))
288 /* [4] */
290 must_go_back = TRUE;
295 ** Here we can be sure that the actual AChain is set up; i.e. it will
296 ** have ac->an_Lock set correctly and to indicate this
297 ** DDF_ExaminedBit was set
300 CurrentDir(ac->an_Lock);
302 if (ac->an_Flags & DDF_PatternBit)
304 if(ExNext(ac->an_Lock, &ac->an_Info))
306 if (MatchPatternNoCase(ac->an_String, ac->an_Info.fib_FileName))
309 ** This file matches the pattern in ac->an_String. If
310 ** there are no more AChains to follow then we have
311 ** found a matching file/directory (a result) -->
312 ** break.
315 if (!ac->an_Child)
317 break;
319 else
321 if (ac->an_Info.fib_DirEntryType < 0)
323 /* This is a file, no chance to follow child
324 AChain. Go to top of "for(;;)" loop */
325 continue;
329 } else {
330 /* Did not match. Go to top of "for(;;)" loop */
331 continue;
334 else
336 error = IoErr();
337 if (error != ERROR_NO_MORE_ENTRIES) goto done;
339 /* [3] */
341 must_go_back = TRUE;
344 } /* if (ac->an_Flags & DDF_PatternBit) */
347 ** Handle the cases where we must (try to) go back to the previous
348 ** AChain. This can happen if the actual AChain turned out to be a
349 ** file although there are still more AChains to follow [1]. Or if
350 ** the actual AChain did not exist at all [2]. Or if in a pattern
351 ** AChain ExNext() told us that there are no more entries [3]. Or if
352 ** we were getting to a normal (no pattern) AChain which was already
353 ** set up (DDF_ExaminedBit) [4].
356 if (must_go_back)
358 /* Check if going back is possible at all */
360 if (!ac->an_Parent)
362 error = ERROR_NO_MORE_ENTRIES;
363 goto done;
366 dir_changed = TRUE;
368 /* Yep. It is possible. So let's cleanup the AChain. */
370 CurrentDir(ac->an_Parent->an_Lock);
372 UnLock(ac->an_Lock);
374 ac->an_Lock = BNULL;
375 ac->an_Flags &= ~DDF_ExaminedBit;
377 /* Make ac and AP->ap_Current point to the previous AChain */
379 AP->ap_Current = ac->an_Parent;
382 ** If this was an APF_DODIR Achain (indicated by DDF_AllBit)
383 ** then the AChain must be unlinked and freed. And the user
384 ** must be informed about the leaving with APF_DIDDIR and
385 ** a "result" in AnchorPath which points to the directory which
386 ** was leaved.
389 if (ac->an_Flags & DDF_AllBit)
391 AP->ap_Current->an_Child = NULL;
392 Match_FreeAChain(ac, DOSBase);
393 AP->ap_Flags |= APF_DIDDIR;
395 /* go out of for(;;) loop --> MakeResult */
397 break;
400 ac = AP->ap_Current;
402 } /* if (must_go_back) */
403 else
405 if (!ac->an_Child)
408 ** We have reached the last AChain. And this means that
409 ** we have found a matching file/directory :-)). Go out of
410 ** for(;;) loop --> MakeResult
413 break;
416 ac = ac->an_Child;
417 AP->ap_Current = ac;
419 dir_changed = TRUE; /* CHECKME!!! Really? */
422 } /* for(;;) */
424 error = Match_MakeResult(AP, DOSBase);
426 done:
427 CurrentDir(origdir);
429 AP->ap_Flags &= ~APF_DODIR;
431 if (dir_changed)
433 AP->ap_Flags |= APF_DirChanged;
435 else
437 AP->ap_Flags &= ~APF_DirChanged;
440 SetIoErr(error);
442 return error;
444 AROS_LIBFUNC_EXIT
446 } /* MatchNext */