2 Copyright © 1995-2001, 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().
36 AP - pointer to Anchor Path structure which had been passed to
48 MatchFirst() MatchEnd() CurrentDir() Examine() ExNext()
49 ParsePattern() <dos/dosasl.h>
53 *****************************************************************************/
56 AROS_LIBBASE_EXT_DECL(struct DosLibrary
*,DOSBase
)
58 struct AChain
*ac
= AP
->ap_Current
;
59 BPTR origdir
, old_current_lock
;
61 BOOL dir_changed
= FALSE
;
63 origdir
= CurrentDir(0);
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
89 if ((ac
->an_Child
= Match_AllocAChain(1, DOSBase
)))
91 ac
->an_Child
->an_Parent
= ac
;
95 ac
->an_String
[0] = P_ANY
;
97 ac
->an_Flags
= DDF_PatternBit
| DDF_AllBit
;
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 */
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
)
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
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
);
148 ac
->an_Lock
= Lock(ac
->an_Parent
->an_String
, SHARED_LOCK
);
157 #if !MATCHFUNCS_NO_DUPLOCK
160 ac
->an_Lock
= DupLock(origdir
);
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
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
186 if (!Examine(ac
->an_Lock
, &ac
->an_Info
))
191 ac
->an_Flags
|= DDF_ExaminedBit
;
193 } /* if (ac->an_Flags & DDF_PatternBit) */
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
))
216 /* if going back is not possible get error code and exit */
221 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
224 /* The File/Direcory ac->an_String exists */
226 success
= Examine(lock
, &ac
->an_Info
);
232 ** Examine()ing the file/directory did not
233 ** work, although the lock was successful!?.
234 ** Get error code and exit
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
260 if (ac
->an_Child
&& (ac
->an_Info
.fib_DirEntryType
< 0))
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)) */
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
))
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) -->
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 */
333 /* Did not match. Go to top of "for(;;)" loop */
340 if (error
!= ERROR_NO_MORE_ENTRIES
) goto done
;
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].
361 /* Check if going back is possible at all */
365 error
= ERROR_NO_MORE_ENTRIES
;
371 /* Yep. It is possible. So let's cleanup the AChain. */
373 CurrentDir(ac
->an_Parent
->an_Lock
);
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
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 */
405 } /* if (must_go_back) */
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
422 dir_changed
= TRUE
; /* CHECKME!!! Really? */
427 error
= Match_MakeResult(AP
, DOSBase
);
432 AP
->ap_Flags
&= ~APF_DODIR
;
436 AP
->ap_Flags
|= APF_DirChanged
;
440 AP
->ap_Flags
&= ~APF_DirChanged
;