Added missing property.
[tangerine.git] / test / newmatch.c
blob35cbcd9d7f469e7dd7b5e5cc22d3e58c4a67f5e8
1 #include <exec/exec.h>
2 #include <dos/dos.h>
3 #include <dos/dosextens.h>
4 #include <dos/dosasl.h>
5 #include <proto/exec.h>
6 #include <proto/dos.h>
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
12 /****************************************************************************************/
14 #define MATCHFUNCS_NO_DUPLOCK 0
16 /****************************************************************************************/
18 #define COMPTYPE_NORMAL 1
19 #define COMPTYPE_PATTERN 2
20 #define COMPTYPE_UNKNOWN 3
22 /****************************************************************************************/
24 LONG My_MatchNext(struct AnchorPath *AP);
26 /****************************************************************************************/
29 static void showacflags(struct AChain *ac)
31 BYTE flags = ac->an_Flags;
33 printf("(");
35 if (flags & DDF_PatternBit)
37 flags &= ~DDF_PatternBit;
38 printf("DDF_PatternBit ");
41 if (flags & DDF_ExaminedBit)
43 flags &= ~DDF_ExaminedBit;
44 printf("DDF_ExaminedBit ");
47 if (flags & DDF_Completed)
49 flags &= ~DDF_Completed;
50 printf("DDF_Completed ");
53 if (flags & DDF_AllBit)
55 flags &= ~DDF_AllBit;
56 printf("DDF_All ");
59 if (flags & DDF_Single)
61 flags &= ~DDF_Single;
62 printf("DDF_Single ");
65 if (flags)
67 printf("UNKNOWN = %8x ", flags);
70 printf(")");
73 static void showaclist(struct AChain *ac)
75 while(ac)
77 printf("achain: address = %p flags = %x ", ac, ac->an_Flags);
78 showacflags(ac);
79 printf(" string=\"%s\"\n", ac->an_String);
80 ac = ac->an_Child;
85 /****************************************************************************************/
87 static void RemoveTrailingSlash(STRPTR s)
89 LONG len = strlen(s);
91 if (len >= 2)
93 if ((s[len - 1] == '/') &&
94 (s[len - 2] != '/'))
96 s[len - 1] = '\0';
101 /****************************************************************************************/
103 static struct AChain *Match_AllocAChain(LONG extrasize, struct DosLibrary *DOSBase)
105 return AllocVec(sizeof(struct AChain) + extrasize, MEMF_PUBLIC | MEMF_CLEAR);
108 /****************************************************************************************/
110 static void Match_FreeAChain(struct AChain *ac, struct DosLibrary *DOSBase)
112 if (ac)
114 FreeVec(ac);
118 /*****************************************************************************************
120 The job of BuildAChainList is to split the pattern string passed to MatchFirst into
121 path components. Most imporant rules (as found out after hours of testing on Amiga):
123 - Each path component containing a pattern string is put into a single AChain
124 - If there are several successive path components *without* pattern then this
125 are merged into one single AChain.
126 - No matter what: the last path component always gets into its own single AChain.
128 Examples: [<???>] is one AChain
130 pictures [pictures]
131 pictures/#? [pictures} [#?]
132 work: [work:] []
133 work:pictures [work:} [pictures]
134 work:pictures/#? [work:pictures] [#?]
135 work:pictures/aros [work:pictures] [aros]
136 work:pictures/aros/games [work:pictures/aros] [games]
137 work:#?/aros/games [work:] [#?] [aros] [games}
138 work:#?/#?/aros/games/quake [work:} [#?] [#?] [aros/games] [quake]
140 *****************************************************************************************/
142 static LONG BuildAChainList(STRPTR pattern, struct AnchorPath *AP,
143 struct AChain **retac, struct DosLibrary *DOSBase)
145 struct AChain *baseac = 0, *prevac = 0, *ac;
146 STRPTR patterncopy = 0;
147 STRPTR patternstart, patternend, patternpos;
148 LONG len, error = 0;
149 WORD comptype = COMPTYPE_UNKNOWN;
150 WORD compcount = 0;
151 WORD i;
152 UBYTE c;
154 *retac = 0;
156 len = strlen(pattern);
158 patterncopy = AllocVec(len + 1, MEMF_PUBLIC);
159 if (!patterncopy)
161 error = ERROR_NO_FREE_STORE;
162 goto done;
165 strcpy(patterncopy, pattern);
167 RemoveTrailingSlash(patterncopy);
169 patternstart = patterncopy;
171 patternpos = strchr(patterncopy, ':');
172 if (!patternpos)
174 comptype = COMPTYPE_UNKNOWN;
175 patternpos = patternstart;
176 patternend = patternstart;
178 else
180 comptype = COMPTYPE_NORMAL;
181 patternend = patternpos++;
182 compcount = 1;
187 for(;;)
189 c = *patternpos;
190 if (c == '/')
192 if (comptype == COMPTYPE_UNKNOWN)
194 comptype = COMPTYPE_NORMAL;
195 patternend = patternpos;
197 else if (comptype == COMPTYPE_NORMAL)
199 patternend = patternpos;
200 compcount++;
202 if (comptype == COMPTYPE_PATTERN)
204 patternend = patternpos;
205 break;
208 else if (c == '\0')
210 if (comptype == COMPTYPE_UNKNOWN)
212 comptype = COMPTYPE_NORMAL;
213 patternend = patternpos;
214 break;
216 if (comptype == COMPTYPE_NORMAL)
218 compcount++;
219 break;
221 patternend = patternpos;
222 break;
224 else if ((c == '#') ||
225 (c == '~') ||
226 (c == '[') ||
227 (c == ']') ||
228 (c == '?') ||
229 (c == '*') ||
230 (c == '(') ||
231 (c == ')') ||
232 (c == '|') ||
233 (c == '%'))
235 if (comptype == COMPTYPE_NORMAL)
237 break;
239 comptype = COMPTYPE_PATTERN;
242 patternpos++;
244 } /* for(;;) */
246 len = (LONG)(patternend - patternstart + 2);
247 if (comptype == COMPTYPE_PATTERN) len = len * 2 + 2;
249 ac = Match_AllocAChain(len, DOSBase);
250 if (!ac)
252 error = ERROR_NO_FREE_STORE;
253 goto done;
256 if (comptype == COMPTYPE_NORMAL)
258 if (*patternend == '\0')
260 strcpy(ac->an_String, patternstart);
261 } else {
262 c = patternend[1];
263 patternend[1] = '\0';
264 strcpy(ac->an_String, patternstart);
265 patternend[1] = c;
268 } /* if (comptype == COMPTYPE_NORMAL) */
269 else
271 if (*patternend == '\0')
273 i = ParsePatternNoCase(patternstart, ac->an_String, len);
275 else
277 c = patternend[1];
278 patternend[1] = '\0';
279 i = ParsePatternNoCase(patternstart, ac->an_String, len);
280 patternend[1] = c;
283 if (i == -1)
285 error = ERROR_BAD_TEMPLATE;
286 Match_FreeAChain(ac, DOSBase);ac = 0;
287 goto done;
290 if (i)
292 ac->an_Flags |= DDF_PatternBit;
293 AP->ap_Flags |= APF_ITSWILD;
296 } /* if (comptype == COMPTYPE_NORMAL) else ... */
298 RemoveTrailingSlash(ac->an_String);
300 if (!prevac)
302 baseac = ac;
304 else
306 prevac->an_Child = ac;
307 ac->an_Parent = prevac;
310 prevac = ac;
312 patternpos = patternend;
313 comptype = COMPTYPE_UNKNOWN;
314 patternstart = patternend = patternpos + 1;
315 compcount = 0;
317 } while (*patternpos++ != '\0');
319 done:
320 if (patterncopy) FreeVec(patterncopy);
322 if (!error)
324 #if MATCHFUNCS_NO_DUPLOCK
326 ** No DupLock() here, because then we would have to UnLock it in MatchEnd
327 ** and we would not know any valid lock to which we could CurrentDir after,
328 ** because we must make sure there is a valid CurrentDir after MatchEnd.
331 baseac->an_Lock = CurrentDir(0);
332 CurrentDir(baseac->an_Lock);
333 #endif
334 *retac = baseac;
336 else
338 AP->ap_Flags |= APF_NOMEMERR;
340 if (baseac)
342 #define nextac prevac /* to not have to add another variable */
344 ac = baseac;
345 while(ac)
347 nextac = ac->an_Child;
348 Match_FreeAChain(ac, DOSBase);
349 ac = nextac;
354 return error;
357 /****************************************************************************************/
359 static LONG Match_MakeResult(struct AnchorPath *AP, struct DosLibrary *DOSBase)
361 LONG error = 0;
363 AP->ap_Info = AP->ap_Current->an_Info;
364 if (AP->ap_Strlen)
366 AP->ap_Buf[0] = 0;
367 if (NameFromLock(AP->ap_Current->an_Lock, AP->ap_Buf, AP->ap_Strlen))
369 if (!AddPart(AP->ap_Buf, AP->ap_Current->an_Info.fib_FileName, AP->ap_Strlen))
371 error = IoErr();
373 } else {
374 error = IoErr();
378 return error;
381 /****************************************************************************************/
383 LONG My_MatchFirst(STRPTR pat, struct AnchorPath *AP)
385 struct AChain *ac;
386 LONG error;
388 AP->ap_Flags = 0;
389 AP->ap_Base = 0;
390 AP->ap_Current = 0;
392 error = BuildAChainList(pat, AP, &ac, DOSBase);
393 if (error == 0)
395 AP->ap_Base = AP->ap_Current = ac;
397 error = My_MatchNext(AP);
399 } /* if (error == 0) */
401 printf("My_MatchFirst: returning %ld. Ac = %p\n", error, ac);
403 SetIoErr(error);
405 return error;
408 /****************************************************************************************/
410 LONG My_MatchNext(struct AnchorPath *AP)
412 struct AChain *ac = AP->ap_Current;
413 BPTR origdir, old_current_lock;
414 LONG error = 0;
416 origdir = CurrentDir(0);
417 CurrentDir(origdir);
419 old_current_lock = ac->an_Lock;
421 AP->ap_Flags &= ~APF_DIDDIR;
424 ** Check if we are asked to enter a directory, but only do this
425 ** if it is really possible
428 if ((AP->ap_Flags & APF_DODIR) &&
429 (ac->an_Flags & DDF_ExaminedBit) &&
430 (ac->an_Info.fib_DirEntryType > 0) &&
431 (ac->an_Child == NULL))
434 ** Alloc a new AChain. Make it the active one. Set its string to "#?" and
435 ** mark it with DDF_AllBit Flag to indicate that this is a "APF_DODIR-AChain".
436 ** This is important for "back steppings", because "APF_DODIR-AChains" must
437 ** be removed and freed then and the user must be notified about the leaving
438 ** of a APF_DODIR-AChain with APF_DIDDIR.
441 if ((ac->an_Child = Match_AllocAChain(1, DOSBase)))
443 ac->an_Child->an_Parent = ac;
444 ac = ac->an_Child;
445 AP->ap_Current = ac;
447 ac->an_String[0] = P_ANY;
448 ac->an_String[1] = 0;
449 ac->an_Flags = DDF_PatternBit | DDF_AllBit;
453 ** If the allocation did not work, we simple ignore APF_DODIR. Just like if
454 ** the user did not set this flag. Good idea or bad idea?
459 /* Main loop for AChain traversing */
461 for(;;)
463 BOOL must_go_back = FALSE;
465 /* Check for user breaks (CTRL_C, ...) */
467 if (AP->ap_BreakBits)
469 AP->ap_FoundBreak = CheckSignal(AP->ap_BreakBits);
470 if (AP->ap_FoundBreak)
472 error = ERROR_BREAK;
473 goto done;
477 /* Check if AChain must be "setup" */
479 if (!(ac->an_Flags & DDF_ExaminedBit))
482 ** This AChain must be "setup". First AChain->an_Lock must point
483 ** to the parent directory, that is the directory where this
484 ** AChain is "in". !
487 if (ac->an_Parent)
489 CurrentDir(ac->an_Parent->an_Lock);
490 ac->an_Lock = Lock(ac->an_Parent->an_Info.fib_FileName, SHARED_LOCK);
492 if (!ac->an_Lock)
494 error = IoErr();
495 goto done;
499 #if !MATCHFUNCS_NO_DUPLOCK
500 else
502 ac->an_Lock = DupLock(origdir);
503 if (!ac->an_Lock)
505 error = IoErr();
506 goto done;
509 #else
511 ** If there was no ac->an_Parent then we are dealing with the
512 ** first AChain whose lock was already setup in BuildAChainList
514 #endif
515 CurrentDir(ac->an_Lock);
517 if (ac->an_Flags & DDF_PatternBit)
520 ** If this is a pattern AChain we first Examine here our
521 ** parent directory, so that it then can be traversed with
522 ** ExNext
525 if (!Examine(ac->an_Lock, &ac->an_Info))
527 error = IoErr();
528 goto done;
530 ac->an_Flags |= DDF_ExaminedBit;
532 } /* if (ac->an_Flags & DDF_PatternBit) */
533 else
535 BPTR lock;
536 LONG success;
539 ** This is a normal AChain (no pattern). Try to lock it
540 ** to see if it exists.
543 if (!(lock = Lock(ac->an_String, SHARED_LOCK)))
545 /* It does not exist, so if possible go back one step */
547 if (ac->an_Parent)
549 /* [2] */
551 must_go_back = TRUE;
553 else
555 /* if going back is not possible get error code and exit */
556 error = IoErr();
557 goto done;
560 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
561 else
563 /* The File/Direcory ac->an_String exists */
565 success = Examine(lock, &ac->an_Info);
566 UnLock(lock);
568 if (!success)
571 ** Examine()ing the file/directory did not
572 ** work, although the lock was successful!?.
573 ** Get error code and exit
576 error = IoErr();
577 goto done;
581 ** This strcpy is necessary, because in case
582 ** of empty ac->an_String("") fib_FileName would
583 ** get parent directory name which it must not!
586 strcpy(ac->an_Info.fib_FileName, ac->an_String);
588 ac->an_Flags |= DDF_ExaminedBit;
591 ** If this is a file, but there are still more path components to
592 ** follow then we have to go back one step (AChain)
595 if (ac->an_Child && (ac->an_Info.fib_DirEntryType < 0))
597 /* [1] */
599 must_go_back = TRUE;
603 ** Here we either have found a matching file/directory (result)
604 ** or, if ac->an_Child != NULL we have still to continue walking
605 ** through the AChains until we are in the last one. This all
606 ** happens further below
609 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) else ... */
611 } /* if (ac->an_Flags & DDF_PatternBit) else ... */
613 } /* if (!(ac->an_Flags & DDF_ExaminedBit)) */
614 else
617 ** This AChain was already setup.
619 ** When an AChain which is *not* a pattern already had DDF_PatternBit
620 ** set, then this means ERROR_NO_MORE_ENTRIES, so we try to go back
621 ** one step
624 if (!(ac->an_Flags & DDF_PatternBit))
626 /* [4] */
628 must_go_back = TRUE;
633 ** Here we can be sure that the actual AChain is setup, ie: it will
634 ** have ac->an_Lock set correctly and to indicate this DDF_ExaminedBit
635 ** was set
638 CurrentDir(ac->an_Lock);
640 if (ac->an_Flags & DDF_PatternBit)
642 if(ExNext(ac->an_Lock, &ac->an_Info))
644 if (MatchPatternNoCase(ac->an_String, ac->an_Info.fib_FileName))
647 ** This file matches the pattern in ac->an_String. If there
648 ** are no more AChains to follow then we have found a matching
649 ** file/directory (a result) --> break.
652 if (!ac->an_Child) break;
654 } else {
655 /* Did not match. Go to top of "for(;;)" loop */
656 continue;
659 else
661 error = IoErr();
662 if (error != ERROR_NO_MORE_ENTRIES) goto done;
664 /* [3] */
666 must_go_back = TRUE;
669 } /* if (ac->an_Flags & DDF_PatternBit) */
672 ** Handle the cases where we must (try to) go back to the previous AChain.
673 ** This can happen if the actual AChain turned out to be a file although
674 ** there are still more AChains to follow [1]. Or if the actual AChain did not
675 ** exist at all [2]. Or if in a pattern AChain ExNext() told us that there are
676 ** no more entries [3]. Or if we were getting to a normal (no pattern) AChain
677 ** which was already setup (DDF_ExaminedBit) [4].
680 if (must_go_back)
682 /* Check if going back is possible at all */
684 if (!ac->an_Parent)
686 error = ERROR_NO_MORE_ENTRIES;
687 goto done;
690 /* Yep. It is possible. So let's cleanup the AChain. */
692 CurrentDir(ac->an_Parent->an_Lock);
694 UnLock(ac->an_Lock);
696 ac->an_Lock = NULL;
697 ac->an_Flags &= ~DDF_ExaminedBit;
699 /* Make ac and AP->ap_Current point to the previous AChain */
701 AP->ap_Current = ac->an_Parent;
704 ** If this was an APF_DODIR Achain (indicated by DDF_AllBit)
705 ** then the AChain must be unlinked and freed. And the user
706 ** must be informed about the leaving with APF_DIDDIR and
707 ** a "result" in AnchorPath which points to the directory which
708 ** was leaved.
711 if (ac->an_Flags & DDF_AllBit)
713 AP->ap_Current->an_Child = NULL;
714 Match_FreeAChain(ac, DOSBase);
715 AP->ap_Flags |= APF_DIDDIR;
717 /* go out of for(;;) loop --> MakeResult */
719 break;
722 ac = AP->ap_Current;
724 } /* if (must_go_back) */
725 else
727 if (!ac->an_Child)
730 ** We have reached the last AChain. And this means that
731 ** we have found a matching file/directory :-)). Go out of
732 ** for(;;) loop --> MakeResult
735 break;
738 ac = ac->an_Child;
739 AP->ap_Current = ac;
742 } /* for(;;) */
744 error = Match_MakeResult(AP, DOSBase);
746 done:
747 CurrentDir(origdir);
749 AP->ap_Flags &= ~APF_DODIR;
751 if (old_current_lock != AP->ap_Current->an_Lock)
753 AP->ap_Flags |= APF_DirChanged;
755 else
757 AP->ap_Flags &= ~APF_DirChanged;
760 SetIoErr(error);
762 return error;
766 /****************************************************************************************/
768 void My_MatchEnd(struct AnchorPath *AP)
770 struct AChain *ac = AP->ap_Base, *acnext;
772 if (ac)
775 #if MATCHFUNCS_NO_DUPLOCK
777 ** CurrentDir to a valid lock, ie. one that will not be
778 ** killed further below
781 CurrentDir(ac->an_Lock);
782 #endif
783 while(ac)
785 acnext = ac->an_Child;
788 ** Dont unlock lock in first AChain because it is the same
789 ** as the current directory when MatchFirst was called. And
790 ** this lock was not DupLock()ed!!!
793 if (ac->an_Lock
794 #if MATCHFUNCS_NO_DUPLOCK
795 && (ac != AP->ap_Base)
796 #endif
799 UnLock(ac->an_Lock);
802 Match_FreeAChain(ac, DOSBase);
804 ac = acnext;
808 AP->ap_Current = NULL;
809 AP->ap_Base = NULL;
812 /****************************************************************************************/
814 #define ARG_TEMPLATE "FILE/A,ALL/S"
815 #define ARG_FILE 0
816 #define ARG_ALL 1
817 #define NUM_ARGS 2
819 /****************************************************************************************/
821 static char s[300];
822 static char *filename;
823 static BOOL all;
824 static struct RDArgs *myargs;
825 static LONG args[NUM_ARGS];
827 /****************************************************************************************/
829 static void cleanup(char *msg)
831 if (msg) printf("newmatch: %s\n", msg);
833 if (myargs) FreeArgs(myargs);
835 exit(0);
838 /****************************************************************************************/
840 static void doserror(void)
842 Fault(IoErr(), 0, s, 255);
843 cleanup(s);
846 /****************************************************************************************/
848 static void getarguments(void)
850 if (!(myargs = ReadArgs(ARG_TEMPLATE, args, 0)))
852 doserror();
855 filename = (char *)args[ARG_FILE];
856 all = args[ARG_ALL] ? TRUE : FALSE;
859 /****************************************************************************************/
861 static void my_matchme(char *pattern, BOOL all)
863 struct AnchorPath stackap[2], *AP;
864 LONG error = 0;
866 AP = (struct AnchorPath *)((((ULONG)stackap) + 3) & ~3);
868 memset(AP, 0, sizeof(struct AnchorPath));
870 error = My_MatchFirst(pattern, AP);
872 if (error != 0)
874 printf("MatchFirst: error = %ld\n", error);
876 else
878 printf("direntrytype = %ld\n", AP->ap_Info.fib_DirEntryType);
879 if (!(AP->ap_Flags & APF_ITSWILD) &&
880 (AP->ap_Info.fib_DirEntryType > 0))
882 /* pattern was an explicitely named directory */
883 AP->ap_Flags |= APF_DODIR;
886 printf("ap_Flags = %x\n", AP->ap_Flags);
887 NameFromLock(AP->ap_Current->an_Lock, s, 300);
888 printf("BaseLock = \"%s\"\n", s);
890 showaclist(AP->ap_Base);
892 while(error == 0)
894 if (AP->ap_Flags & APF_DIDDIR)
896 printf("DIDDIR: ");
897 } else {
898 if (all && (AP->ap_Info.fib_DirEntryType > 0))
900 AP->ap_Flags |= APF_DODIR;
901 printf("DOING DIR: ");
904 printf("fib_FileName = \"%s\"\n", AP->ap_Info.fib_FileName);
906 error = My_MatchNext(AP);
911 My_MatchEnd(AP);
915 /****************************************************************************************/
916 /****************************************************************************************/
918 int main(void)
920 getarguments();
921 my_matchme(filename, all);
922 cleanup(0);
923 return 0;
926 /****************************************************************************************/