2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
8 #include <dos/dosextens.h>
9 #include <dos/dosasl.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
17 /****************************************************************************************/
19 #define MATCHFUNCS_NO_DUPLOCK 0
21 /****************************************************************************************/
23 #define COMPTYPE_NORMAL 1
24 #define COMPTYPE_PATTERN 2
25 #define COMPTYPE_UNKNOWN 3
27 /****************************************************************************************/
29 LONG
My_MatchNext(struct AnchorPath
*AP
);
31 /****************************************************************************************/
34 static void showacflags(struct AChain
*ac
)
36 BYTE flags
= ac
->an_Flags
;
40 if (flags
& DDF_PatternBit
)
42 flags
&= ~DDF_PatternBit
;
43 printf("DDF_PatternBit ");
46 if (flags
& DDF_ExaminedBit
)
48 flags
&= ~DDF_ExaminedBit
;
49 printf("DDF_ExaminedBit ");
52 if (flags
& DDF_Completed
)
54 flags
&= ~DDF_Completed
;
55 printf("DDF_Completed ");
58 if (flags
& DDF_AllBit
)
64 if (flags
& DDF_Single
)
67 printf("DDF_Single ");
72 printf("UNKNOWN = %8x ", flags
);
78 static void showaclist(struct AChain
*ac
)
82 printf("achain: address = %p flags = %x ", ac
, ac
->an_Flags
);
84 printf(" string=\"%s\"\n", ac
->an_String
);
90 /****************************************************************************************/
92 static void RemoveTrailingSlash(STRPTR s
)
98 if ((s
[len
- 1] == '/') &&
106 /****************************************************************************************/
108 static struct AChain
*Match_AllocAChain(LONG extrasize
, struct DosLibrary
*DOSBase
)
110 return AllocVec(sizeof(struct AChain
) + extrasize
, MEMF_PUBLIC
| MEMF_CLEAR
);
113 /****************************************************************************************/
115 static void Match_FreeAChain(struct AChain
*ac
, struct DosLibrary
*DOSBase
)
120 /*****************************************************************************************
122 The job of BuildAChainList is to split the pattern string passed to MatchFirst into
123 path components. Most imporant rules (as found out after hours of testing on Amiga):
125 - Each path component containing a pattern string is put into a single AChain
126 - If there are several successive path components *without* pattern then this
127 are merged into one single AChain.
128 - No matter what: the last path component always gets into its own single AChain.
130 Examples: [<???>] is one AChain
133 pictures/#? [pictures} [#?]
135 work:pictures [work:} [pictures]
136 work:pictures/#? [work:pictures] [#?]
137 work:pictures/aros [work:pictures] [aros]
138 work:pictures/aros/games [work:pictures/aros] [games]
139 work:#?/aros/games [work:] [#?] [aros] [games}
140 work:#?/#?/aros/games/quake [work:} [#?] [#?] [aros/games] [quake]
142 *****************************************************************************************/
144 static LONG
BuildAChainList(STRPTR pattern
, struct AnchorPath
*AP
,
145 struct AChain
**retac
, struct DosLibrary
*DOSBase
)
147 struct AChain
*baseac
= 0, *prevac
= 0, *ac
;
148 STRPTR patterncopy
= 0;
149 STRPTR patternstart
, patternend
, patternpos
;
151 WORD comptype
= COMPTYPE_UNKNOWN
;
158 len
= strlen(pattern
);
160 patterncopy
= AllocVec(len
+ 1, MEMF_PUBLIC
);
163 error
= ERROR_NO_FREE_STORE
;
167 strcpy(patterncopy
, pattern
);
169 RemoveTrailingSlash(patterncopy
);
171 patternstart
= patterncopy
;
173 patternpos
= strchr(patterncopy
, ':');
176 comptype
= COMPTYPE_UNKNOWN
;
177 patternpos
= patternstart
;
178 patternend
= patternstart
;
182 comptype
= COMPTYPE_NORMAL
;
183 patternend
= patternpos
++;
194 if (comptype
== COMPTYPE_UNKNOWN
)
196 comptype
= COMPTYPE_NORMAL
;
197 patternend
= patternpos
;
199 else if (comptype
== COMPTYPE_NORMAL
)
201 patternend
= patternpos
;
204 if (comptype
== COMPTYPE_PATTERN
)
206 patternend
= patternpos
;
212 if (comptype
== COMPTYPE_UNKNOWN
)
214 comptype
= COMPTYPE_NORMAL
;
215 patternend
= patternpos
;
218 if (comptype
== COMPTYPE_NORMAL
)
223 patternend
= patternpos
;
226 else if ((c
== '#') ||
237 if (comptype
== COMPTYPE_NORMAL
)
241 comptype
= COMPTYPE_PATTERN
;
248 len
= (LONG
)(patternend
- patternstart
+ 2);
249 if (comptype
== COMPTYPE_PATTERN
) len
= len
* 2 + 2;
251 ac
= Match_AllocAChain(len
, DOSBase
);
254 error
= ERROR_NO_FREE_STORE
;
258 if (comptype
== COMPTYPE_NORMAL
)
260 if (*patternend
== '\0')
262 strcpy(ac
->an_String
, patternstart
);
265 patternend
[1] = '\0';
266 strcpy(ac
->an_String
, patternstart
);
270 } /* if (comptype == COMPTYPE_NORMAL) */
273 if (*patternend
== '\0')
275 i
= ParsePatternNoCase(patternstart
, ac
->an_String
, len
);
280 patternend
[1] = '\0';
281 i
= ParsePatternNoCase(patternstart
, ac
->an_String
, len
);
287 error
= ERROR_BAD_TEMPLATE
;
288 Match_FreeAChain(ac
, DOSBase
);ac
= 0;
294 ac
->an_Flags
|= DDF_PatternBit
;
295 AP
->ap_Flags
|= APF_ITSWILD
;
298 } /* if (comptype == COMPTYPE_NORMAL) else ... */
300 RemoveTrailingSlash(ac
->an_String
);
308 prevac
->an_Child
= ac
;
309 ac
->an_Parent
= prevac
;
314 patternpos
= patternend
;
315 comptype
= COMPTYPE_UNKNOWN
;
316 patternstart
= patternend
= patternpos
+ 1;
319 } while (*patternpos
++ != '\0');
322 FreeVec(patterncopy
);
326 #if MATCHFUNCS_NO_DUPLOCK
328 ** No DupLock() here, because then we would have to UnLock it in MatchEnd
329 ** and we would not know any valid lock to which we could CurrentDir after,
330 ** because we must make sure there is a valid CurrentDir after MatchEnd.
333 baseac
->an_Lock
= CurrentDir(0);
334 CurrentDir(baseac
->an_Lock
);
340 AP
->ap_Flags
|= APF_NOMEMERR
;
344 #define nextac prevac /* to not have to add another variable */
349 nextac
= ac
->an_Child
;
350 Match_FreeAChain(ac
, DOSBase
);
359 /****************************************************************************************/
361 static LONG
Match_MakeResult(struct AnchorPath
*AP
, struct DosLibrary
*DOSBase
)
365 AP
->ap_Info
= AP
->ap_Current
->an_Info
;
369 if (NameFromLock(AP
->ap_Current
->an_Lock
, AP
->ap_Buf
, AP
->ap_Strlen
))
371 if (!AddPart(AP
->ap_Buf
, AP
->ap_Current
->an_Info
.fib_FileName
, AP
->ap_Strlen
))
383 /****************************************************************************************/
385 LONG
My_MatchFirst(STRPTR pat
, struct AnchorPath
*AP
)
394 error
= BuildAChainList(pat
, AP
, &ac
, DOSBase
);
397 AP
->ap_Base
= AP
->ap_Current
= ac
;
399 error
= My_MatchNext(AP
);
401 } /* if (error == 0) */
403 printf("My_MatchFirst: returning %ld. Ac = %p\n", (long)error
, ac
);
410 /****************************************************************************************/
412 LONG
My_MatchNext(struct AnchorPath
*AP
)
414 struct AChain
*ac
= AP
->ap_Current
;
415 BPTR origdir
, old_current_lock
;
418 origdir
= CurrentDir(0);
421 old_current_lock
= ac
->an_Lock
;
423 AP
->ap_Flags
&= ~APF_DIDDIR
;
426 ** Check if we are asked to enter a directory, but only do this
427 ** if it is really possible
430 if ((AP
->ap_Flags
& APF_DODIR
) &&
431 (ac
->an_Flags
& DDF_ExaminedBit
) &&
432 (ac
->an_Info
.fib_DirEntryType
> 0) &&
433 (ac
->an_Child
== NULL
))
436 ** Alloc a new AChain. Make it the active one. Set its string to "#?" and
437 ** mark it with DDF_AllBit Flag to indicate that this is a "APF_DODIR-AChain".
438 ** This is important for "back steppings", because "APF_DODIR-AChains" must
439 ** be removed and freed then and the user must be notified about the leaving
440 ** of a APF_DODIR-AChain with APF_DIDDIR.
443 if ((ac
->an_Child
= Match_AllocAChain(1, DOSBase
)))
445 ac
->an_Child
->an_Parent
= ac
;
449 ac
->an_String
[0] = P_ANY
;
450 ac
->an_String
[1] = 0;
451 ac
->an_Flags
= DDF_PatternBit
| DDF_AllBit
;
455 ** If the allocation did not work, we simple ignore APF_DODIR. Just like if
456 ** the user did not set this flag. Good idea or bad idea?
461 /* Main loop for AChain traversing */
465 BOOL must_go_back
= FALSE
;
467 /* Check for user breaks (CTRL_C, ...) */
469 if (AP
->ap_BreakBits
)
471 AP
->ap_FoundBreak
= CheckSignal(AP
->ap_BreakBits
);
472 if (AP
->ap_FoundBreak
)
479 /* Check if AChain must be "setup" */
481 if (!(ac
->an_Flags
& DDF_ExaminedBit
))
484 ** This AChain must be "setup". First AChain->an_Lock must point
485 ** to the parent directory, that is the directory where this
491 CurrentDir(ac
->an_Parent
->an_Lock
);
492 ac
->an_Lock
= Lock(ac
->an_Parent
->an_Info
.fib_FileName
, SHARED_LOCK
);
501 #if !MATCHFUNCS_NO_DUPLOCK
504 ac
->an_Lock
= DupLock(origdir
);
513 ** If there was no ac->an_Parent then we are dealing with the
514 ** first AChain whose lock was already setup in BuildAChainList
517 CurrentDir(ac
->an_Lock
);
519 if (ac
->an_Flags
& DDF_PatternBit
)
522 ** If this is a pattern AChain we first Examine here our
523 ** parent directory, so that it then can be traversed with
527 if (!Examine(ac
->an_Lock
, &ac
->an_Info
))
532 ac
->an_Flags
|= DDF_ExaminedBit
;
534 } /* if (ac->an_Flags & DDF_PatternBit) */
541 ** This is a normal AChain (no pattern). Try to lock it
542 ** to see if it exists.
545 if (!(lock
= Lock(ac
->an_String
, SHARED_LOCK
)))
547 /* It does not exist, so if possible go back one step */
557 /* if going back is not possible get error code and exit */
562 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
565 /* The File/Direcory ac->an_String exists */
567 success
= Examine(lock
, &ac
->an_Info
);
573 ** Examine()ing the file/directory did not
574 ** work, although the lock was successful!?.
575 ** Get error code and exit
583 ** This strcpy is necessary, because in case
584 ** of empty ac->an_String("") fib_FileName would
585 ** get parent directory name which it must not!
588 strcpy(ac
->an_Info
.fib_FileName
, ac
->an_String
);
590 ac
->an_Flags
|= DDF_ExaminedBit
;
593 ** If this is a file, but there are still more path components to
594 ** follow then we have to go back one step (AChain)
597 if (ac
->an_Child
&& (ac
->an_Info
.fib_DirEntryType
< 0))
605 ** Here we either have found a matching file/directory (result)
606 ** or, if ac->an_Child != NULL we have still to continue walking
607 ** through the AChains until we are in the last one. This all
608 ** happens further below
611 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) else ... */
613 } /* if (ac->an_Flags & DDF_PatternBit) else ... */
615 } /* if (!(ac->an_Flags & DDF_ExaminedBit)) */
619 ** This AChain was already setup.
621 ** When an AChain which is *not* a pattern already had DDF_PatternBit
622 ** set, then this means ERROR_NO_MORE_ENTRIES, so we try to go back
626 if (!(ac
->an_Flags
& DDF_PatternBit
))
635 ** Here we can be sure that the actual AChain is setup, ie: it will
636 ** have ac->an_Lock set correctly and to indicate this DDF_ExaminedBit
640 CurrentDir(ac
->an_Lock
);
642 if (ac
->an_Flags
& DDF_PatternBit
)
644 if(ExNext(ac
->an_Lock
, &ac
->an_Info
))
646 if (MatchPatternNoCase(ac
->an_String
, ac
->an_Info
.fib_FileName
))
649 ** This file matches the pattern in ac->an_String. If there
650 ** are no more AChains to follow then we have found a matching
651 ** file/directory (a result) --> break.
654 if (!ac
->an_Child
) break;
657 /* Did not match. Go to top of "for(;;)" loop */
664 if (error
!= ERROR_NO_MORE_ENTRIES
) goto done
;
671 } /* if (ac->an_Flags & DDF_PatternBit) */
674 ** Handle the cases where we must (try to) go back to the previous AChain.
675 ** This can happen if the actual AChain turned out to be a file although
676 ** there are still more AChains to follow [1]. Or if the actual AChain did not
677 ** exist at all [2]. Or if in a pattern AChain ExNext() told us that there are
678 ** no more entries [3]. Or if we were getting to a normal (no pattern) AChain
679 ** which was already setup (DDF_ExaminedBit) [4].
684 /* Check if going back is possible at all */
688 error
= ERROR_NO_MORE_ENTRIES
;
692 /* Yep. It is possible. So let's cleanup the AChain. */
694 CurrentDir(ac
->an_Parent
->an_Lock
);
699 ac
->an_Flags
&= ~DDF_ExaminedBit
;
701 /* Make ac and AP->ap_Current point to the previous AChain */
703 AP
->ap_Current
= ac
->an_Parent
;
706 ** If this was an APF_DODIR Achain (indicated by DDF_AllBit)
707 ** then the AChain must be unlinked and freed. And the user
708 ** must be informed about the leaving with APF_DIDDIR and
709 ** a "result" in AnchorPath which points to the directory which
713 if (ac
->an_Flags
& DDF_AllBit
)
715 AP
->ap_Current
->an_Child
= NULL
;
716 Match_FreeAChain(ac
, DOSBase
);
717 AP
->ap_Flags
|= APF_DIDDIR
;
719 /* go out of for(;;) loop --> MakeResult */
726 } /* if (must_go_back) */
732 ** We have reached the last AChain. And this means that
733 ** we have found a matching file/directory :-)). Go out of
734 ** for(;;) loop --> MakeResult
746 error
= Match_MakeResult(AP
, DOSBase
);
751 AP
->ap_Flags
&= ~APF_DODIR
;
753 if (old_current_lock
!= AP
->ap_Current
->an_Lock
)
755 AP
->ap_Flags
|= APF_DirChanged
;
759 AP
->ap_Flags
&= ~APF_DirChanged
;
768 /****************************************************************************************/
770 void My_MatchEnd(struct AnchorPath
*AP
)
772 struct AChain
*ac
= AP
->ap_Base
, *acnext
;
777 #if MATCHFUNCS_NO_DUPLOCK
779 ** CurrentDir to a valid lock, ie. one that will not be
780 ** killed further below
783 CurrentDir(ac
->an_Lock
);
787 acnext
= ac
->an_Child
;
790 ** Dont unlock lock in first AChain because it is the same
791 ** as the current directory when MatchFirst was called. And
792 ** this lock was not DupLock()ed!!!
796 #if MATCHFUNCS_NO_DUPLOCK
797 && (ac
!= AP
->ap_Base
)
804 Match_FreeAChain(ac
, DOSBase
);
810 AP
->ap_Current
= NULL
;
814 /****************************************************************************************/
816 #define ARG_TEMPLATE "FILE/A,ALL/S"
821 /****************************************************************************************/
824 static char *filename
;
826 static struct RDArgs
*myargs
;
827 static IPTR args
[NUM_ARGS
];
829 /****************************************************************************************/
831 static void cleanup(char *msg
)
833 if (msg
) printf("newmatch: %s\n", msg
);
835 if (myargs
) FreeArgs(myargs
);
840 /****************************************************************************************/
842 static void doserror(void)
844 Fault(IoErr(), 0, s
, 255);
848 /****************************************************************************************/
850 static void getarguments(void)
852 if (!(myargs
= ReadArgs(ARG_TEMPLATE
, args
, 0)))
857 filename
= (char *)args
[ARG_FILE
];
858 all
= args
[ARG_ALL
] ? TRUE
: FALSE
;
861 /****************************************************************************************/
863 static void my_matchme(char *pattern
, BOOL all
)
865 struct AnchorPath stackap
[2], *AP
;
868 AP
= (struct AnchorPath
*)((((IPTR
)stackap
) + 3) & ~3);
870 memset(AP
, 0, sizeof(struct AnchorPath
));
872 error
= My_MatchFirst(pattern
, AP
);
876 printf("MatchFirst: error = %d\n", (int)error
);
880 printf("direntrytype = %d\n", (int)AP
->ap_Info
.fib_DirEntryType
);
881 if (!(AP
->ap_Flags
& APF_ITSWILD
) &&
882 (AP
->ap_Info
.fib_DirEntryType
> 0))
884 /* pattern was an explicitely named directory */
885 AP
->ap_Flags
|= APF_DODIR
;
888 printf("ap_Flags = %x\n", AP
->ap_Flags
);
889 NameFromLock(AP
->ap_Current
->an_Lock
, s
, 300);
890 printf("BaseLock = \"%s\"\n", s
);
892 showaclist(AP
->ap_Base
);
896 if (AP
->ap_Flags
& APF_DIDDIR
)
900 if (all
&& (AP
->ap_Info
.fib_DirEntryType
> 0))
902 AP
->ap_Flags
|= APF_DODIR
;
903 printf("DOING DIR: ");
906 printf("fib_FileName = \"%s\"\n", AP
->ap_Info
.fib_FileName
);
908 error
= My_MatchNext(AP
);
917 /****************************************************************************************/
918 /****************************************************************************************/
923 my_matchme(filename
, all
);
928 /****************************************************************************************/