2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
8 #include <exec/memory.h>
9 #include <exec/types.h>
11 #include <proto/exec.h>
12 #include "dos_intern.h"
14 #include <aros/debug.h>
16 /*****************************************************************************
19 #include <dos/dosasl.h>
20 #include <proto/dos.h>
22 AROS_LH1(LONG
, MatchNext
,
25 AROS_LHA(struct AnchorPath
*, AP
, D1
),
28 struct DosLibrary
*, DOSBase
, 138, Dos
)
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 AP - pointer to Anchor Path structure which had been passed to
39 Zero on success, or error code on failure.
48 MatchFirst() MatchEnd() CurrentDir() Examine() ExNext()
49 ParsePattern() <dos/dosasl.h>
53 *****************************************************************************/
57 struct AChain
*ac
= AP
->ap_Current
;
58 BPTR origdir
, old_current_lock
;
60 BOOL dir_changed
= FALSE
;
62 origdir
= CurrentDir(0);
65 old_current_lock
= ac
->an_Lock
;
67 AP
->ap_Flags
&= ~APF_DIDDIR
;
70 ** Check if we are asked to enter a directory, but only do this
71 ** if it is really possible
74 if ((AP
->ap_Flags
& APF_DODIR
) &&
75 (ac
->an_Flags
& DDF_ExaminedBit
) &&
76 (ac
->an_Info
.fib_DirEntryType
> 0) &&
77 (ac
->an_Child
== NULL
))
80 ** Alloc a new AChain. Make it the active one. Set its string to
81 ** "#?" and mark it with DDF_AllBit Flag to indicate that this is a
82 ** "APF_DODIR-AChain". This is important for "back steppings",
83 ** because "APF_DODIR-AChains" must be removed and freed then and
84 ** the user must be notified about the leaving of a APF_DODIR-AChain
88 if ((ac
->an_Child
= Match_AllocAChain(1, DOSBase
)))
90 ac
->an_Child
->an_Parent
= ac
;
94 ac
->an_String
[0] = P_ANY
;
96 ac
->an_Flags
= DDF_PatternBit
| DDF_AllBit
;
102 ** If the allocation did not work, we simple ignore APF_DODIR. Just
103 ** like if the user did not set this flag. Good idea or bad idea?
108 /* Main loop for AChain traversing */
112 BOOL must_go_back
= FALSE
;
114 /* Check for user breaks (CTRL_C, ...) */
116 if (AP
->ap_BreakBits
)
118 AP
->ap_FoundBreak
= CheckSignal(AP
->ap_BreakBits
);
119 if (AP
->ap_FoundBreak
)
126 /* Check if AChain must be "setup" */
128 if (!(ac
->an_Flags
& DDF_ExaminedBit
))
131 ** This AChain must be "setup". First AChain->an_Lock must point
132 ** to the parent directory, that is the directory where this
140 CurrentDir(ac
->an_Parent
->an_Lock
);
141 if (ac
->an_Parent
->an_Flags
& DDF_PatternBit
)
143 ac
->an_Lock
= Lock(ac
->an_Parent
->an_Info
.fib_FileName
, SHARED_LOCK
);
147 ac
->an_Lock
= Lock(ac
->an_Parent
->an_String
, SHARED_LOCK
);
156 #if !MATCHFUNCS_NO_DUPLOCK
159 ac
->an_Lock
= DupLock(origdir
);
170 ** If there was no ac->an_Parent then we are dealing with the
171 ** first AChain whose lock was already setup in
172 ** Match_BuildAChainList
176 CurrentDir(ac
->an_Lock
);
178 if (ac
->an_Flags
& DDF_PatternBit
)
181 ** If this is a pattern AChain we first Examine here our
182 ** parent directory, so that it then can be traversed with
185 if (!Examine(ac
->an_Lock
, &ac
->an_Info
))
190 ac
->an_Flags
|= DDF_ExaminedBit
;
192 } /* if (ac->an_Flags & DDF_PatternBit) */
199 ** This is a normal AChain (no pattern). Try to lock it
200 ** to see if it exists.
203 if (!(lock
= Lock(ac
->an_String
, SHARED_LOCK
)))
205 /* It does not exist, so if possible go back one step */
207 if ((AP
->ap_Flags
& APF_ITSWILD
) && (ac
->an_Parent
))
215 /* if going back is not possible get error code and exit */
220 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
223 /* The File/Direcory ac->an_String exists */
225 success
= Examine(lock
, &ac
->an_Info
);
231 ** Examine()ing the file/directory did not
232 ** work, although the lock was successful!?.
233 ** Get error code and exit
241 ** This strcpy is necessary, because in case
242 ** of empty ac->an_String("") fib_FileName would
243 ** get parent directory name which it must not!
246 if (*ac
->an_String
== '\0')
248 strcpy(ac
->an_Info
.fib_FileName
, ac
->an_String
);
251 ac
->an_Flags
|= DDF_ExaminedBit
;
254 ** If this is a file, but there are still more path
255 ** components to follow then we have to go back one step
259 if (ac
->an_Child
&& (ac
->an_Info
.fib_DirEntryType
< 0))
267 ** Here we either have found a matching file/directory
268 ** (result) or, if ac->an_Child != NULL we have still to
269 ** continue walking through the AChains until we are in
270 ** the last one. This all happens further below
273 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) else ... */
275 } /* if (ac->an_Flags & DDF_PatternBit) else ... */
277 } /* if (!(ac->an_Flags & DDF_ExaminedBit)) */
281 ** This AChain was already setup.
283 ** When an AChain which is *not* a pattern already had
284 ** DDF_PatternBit set, then this means ERROR_NO_MORE_ENTRIES, so
285 ** we try to go back one step
288 if (!(ac
->an_Flags
& DDF_PatternBit
))
297 ** Here we can be sure that the actual AChain is setup, ie: it will
298 ** have ac->an_Lock set correctly and to indicate this
299 ** DDF_ExaminedBit was set
302 CurrentDir(ac
->an_Lock
);
304 if (ac
->an_Flags
& DDF_PatternBit
)
306 if(ExNext(ac
->an_Lock
, &ac
->an_Info
))
308 if (MatchPatternNoCase(ac
->an_String
, ac
->an_Info
.fib_FileName
))
311 ** This file matches the pattern in ac->an_String. If
312 ** there are no more AChains to follow then we have
313 ** found a matching file/directory (a result) -->
323 if (ac
->an_Info
.fib_DirEntryType
< 0)
325 /* This is a file, no chance to follow child
326 AChain. Go to top of "for(;;)" loop */
332 /* Did not match. Go to top of "for(;;)" loop */
339 if (error
!= ERROR_NO_MORE_ENTRIES
) goto done
;
346 } /* if (ac->an_Flags & DDF_PatternBit) */
349 ** Handle the cases where we must (try to) go back to the previous
350 ** AChain. This can happen if the actual AChain turned out to be a
351 ** file although there are still more AChains to follow [1]. Or if
352 ** the actual AChain did not exist at all [2]. Or if in a pattern
353 ** AChain ExNext() told us that there are no more entries [3]. Or if
354 ** we were getting to a normal (no pattern) AChain which was already
355 ** setup (DDF_ExaminedBit) [4].
360 /* Check if going back is possible at all */
364 error
= ERROR_NO_MORE_ENTRIES
;
370 /* Yep. It is possible. So let's cleanup the AChain. */
372 CurrentDir(ac
->an_Parent
->an_Lock
);
377 ac
->an_Flags
&= ~DDF_ExaminedBit
;
379 /* Make ac and AP->ap_Current point to the previous AChain */
381 AP
->ap_Current
= ac
->an_Parent
;
384 ** If this was an APF_DODIR Achain (indicated by DDF_AllBit)
385 ** then the AChain must be unlinked and freed. And the user
386 ** must be informed about the leaving with APF_DIDDIR and
387 ** a "result" in AnchorPath which points to the directory which
391 if (ac
->an_Flags
& DDF_AllBit
)
393 AP
->ap_Current
->an_Child
= NULL
;
394 Match_FreeAChain(ac
, DOSBase
);
395 AP
->ap_Flags
|= APF_DIDDIR
;
397 /* go out of for(;;) loop --> MakeResult */
404 } /* if (must_go_back) */
410 ** We have reached the last AChain. And this means that
411 ** we have found a matching file/directory :-)). Go out of
412 ** for(;;) loop --> MakeResult
421 dir_changed
= TRUE
; /* CHECKME!!! Really? */
426 error
= Match_MakeResult(AP
, DOSBase
);
431 AP
->ap_Flags
&= ~APF_DODIR
;
435 AP
->ap_Flags
|= APF_DirChanged
;
439 AP
->ap_Flags
&= ~APF_DirChanged
;