2 Copyright © 1995-2013, 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
;
60 BOOL dir_changed
= FALSE
;
62 origdir
= CurrentDir(0);
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
86 if ((ac
->an_Child
= Match_AllocAChain(1, DOSBase
)))
88 ac
->an_Child
->an_Parent
= ac
;
92 ac
->an_String
[0] = P_ANY
;
94 ac
->an_Flags
= DDF_PatternBit
| DDF_AllBit
;
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 */
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
)
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
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
);
145 ac
->an_Lock
= Lock(ac
->an_Parent
->an_String
, SHARED_LOCK
);
154 #if !MATCHFUNCS_NO_DUPLOCK
157 ac
->an_Lock
= DupLock(origdir
);
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
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
183 if (!Examine(ac
->an_Lock
, &ac
->an_Info
))
188 ac
->an_Flags
|= DDF_ExaminedBit
;
190 } /* if (ac->an_Flags & DDF_PatternBit) */
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
))
213 /* if going back is not possible get error code and exit */
218 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
221 /* The File/Direcory ac->an_String exists */
223 success
= Examine(lock
, &ac
->an_Info
);
229 ** Examine()ing the file/directory did not
230 ** work, although the lock was successful!?.
231 ** Get error code and exit
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
257 if (ac
->an_Child
&& (ac
->an_Info
.fib_DirEntryType
< 0))
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)) */
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
))
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) -->
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 */
330 /* Did not match. Go to top of "for(;;)" loop */
337 if (error
!= ERROR_NO_MORE_ENTRIES
) goto done
;
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].
358 /* Check if going back is possible at all */
362 error
= ERROR_NO_MORE_ENTRIES
;
368 /* Yep. It is possible. So let's cleanup the AChain. */
370 CurrentDir(ac
->an_Parent
->an_Lock
);
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
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 */
402 } /* if (must_go_back) */
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
419 dir_changed
= TRUE
; /* CHECKME!!! Really? */
424 error
= Match_MakeResult(AP
, DOSBase
);
429 AP
->ap_Flags
&= ~APF_DODIR
;
433 AP
->ap_Flags
|= APF_DirChanged
;
437 AP
->ap_Flags
&= ~APF_DirChanged
;