Update to lasso handling. Adjust scroll amount based on difference between mouse...
[AROS.git] / rom / dos / matchnext.c
blob2d9fa61a435ffbc02f7d873296aa91f4f29e25d6
1 /*
2 Copyright © 1995-2007, 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, old_current_lock;
59 LONG error = 0;
60 BOOL dir_changed = FALSE;
62 origdir = CurrentDir(0);
63 CurrentDir(origdir);
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
85 ** with APF_DIDDIR.
88 if ((ac->an_Child = Match_AllocAChain(1, DOSBase)))
90 ac->an_Child->an_Parent = ac;
91 ac = ac->an_Child;
92 AP->ap_Current = ac;
94 ac->an_String[0] = P_ANY;
95 ac->an_String[1] = 0;
96 ac->an_Flags = DDF_PatternBit | DDF_AllBit;
98 dir_changed = TRUE;
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 */
110 for(;;)
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)
121 error = ERROR_BREAK;
122 goto done;
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
133 ** AChain is "in". !
136 dir_changed = TRUE;
138 if (ac->an_Parent)
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);
145 else
147 ac->an_Lock = Lock(ac->an_Parent->an_String, SHARED_LOCK);
150 if (!ac->an_Lock)
152 error = IoErr();
153 goto done;
156 #if !MATCHFUNCS_NO_DUPLOCK
157 else
159 ac->an_Lock = DupLock(origdir);
161 if (!ac->an_Lock)
163 error = IoErr();
164 goto done;
168 #else
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
174 #endif
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
183 ** ExNext
185 if (!Examine(ac->an_Lock, &ac->an_Info))
187 error = IoErr();
188 goto done;
190 ac->an_Flags |= DDF_ExaminedBit;
192 } /* if (ac->an_Flags & DDF_PatternBit) */
193 else
195 BPTR lock;
196 LONG success;
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))
209 /* [2] */
211 must_go_back = TRUE;
213 else
215 /* if going back is not possible get error code and exit */
216 error = IoErr();
217 goto done;
220 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
221 else
223 /* The File/Direcory ac->an_String exists */
225 success = Examine(lock, &ac->an_Info);
226 UnLock(lock);
228 if (!success)
231 ** Examine()ing the file/directory did not
232 ** work, although the lock was successful!?.
233 ** Get error code and exit
236 error = IoErr();
237 goto done;
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
256 ** (AChain)
259 if (ac->an_Child && (ac->an_Info.fib_DirEntryType < 0))
261 /* [1] */
263 must_go_back = TRUE;
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)) */
278 else
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))
290 /* [4] */
292 must_go_back = TRUE;
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) -->
314 ** break.
317 if (!ac->an_Child)
319 break;
321 else
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 */
327 continue;
331 } else {
332 /* Did not match. Go to top of "for(;;)" loop */
333 continue;
336 else
338 error = IoErr();
339 if (error != ERROR_NO_MORE_ENTRIES) goto done;
341 /* [3] */
343 must_go_back = TRUE;
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].
358 if (must_go_back)
360 /* Check if going back is possible at all */
362 if (!ac->an_Parent)
364 error = ERROR_NO_MORE_ENTRIES;
365 goto done;
368 dir_changed = TRUE;
370 /* Yep. It is possible. So let's cleanup the AChain. */
372 CurrentDir(ac->an_Parent->an_Lock);
374 UnLock(ac->an_Lock);
376 ac->an_Lock = NULL;
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
388 ** was leaved.
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 */
399 break;
402 ac = AP->ap_Current;
404 } /* if (must_go_back) */
405 else
407 if (!ac->an_Child)
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
415 break;
418 ac = ac->an_Child;
419 AP->ap_Current = ac;
421 dir_changed = TRUE; /* CHECKME!!! Really? */
424 } /* for(;;) */
426 error = Match_MakeResult(AP, DOSBase);
428 done:
429 CurrentDir(origdir);
431 AP->ap_Flags &= ~APF_DODIR;
433 if (dir_changed)
435 AP->ap_Flags |= APF_DirChanged;
437 else
439 AP->ap_Flags &= ~APF_DirChanged;
442 SetIoErr(error);
444 return error;
446 AROS_LIBFUNC_EXIT
448 } /* MatchNext */