Tabs to spaces.
[AROS.git] / test / newmatch.c
blob17c04e070db5a701e2b1a0b8a3cb9df46b216cd1
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/exec.h>
7 #include <dos/dos.h>
8 #include <dos/dosextens.h>
9 #include <dos/dosasl.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.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;
38 printf("(");
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)
60 flags &= ~DDF_AllBit;
61 printf("DDF_All ");
64 if (flags & DDF_Single)
66 flags &= ~DDF_Single;
67 printf("DDF_Single ");
70 if (flags)
72 printf("UNKNOWN = %8x ", flags);
75 printf(")");
78 static void showaclist(struct AChain *ac)
80 while(ac)
82 printf("achain: address = %p flags = %x ", ac, ac->an_Flags);
83 showacflags(ac);
84 printf(" string=\"%s\"\n", ac->an_String);
85 ac = ac->an_Child;
90 /****************************************************************************************/
92 static void RemoveTrailingSlash(STRPTR s)
94 LONG len = strlen(s);
96 if (len >= 2)
98 if ((s[len - 1] == '/') &&
99 (s[len - 2] != '/'))
101 s[len - 1] = '\0';
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)
117 FreeVec(ac);
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
132 pictures [pictures]
133 pictures/#? [pictures} [#?]
134 work: [work:] []
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;
150 LONG len, error = 0;
151 WORD comptype = COMPTYPE_UNKNOWN;
152 WORD compcount = 0;
153 WORD i;
154 UBYTE c;
156 *retac = 0;
158 len = strlen(pattern);
160 patterncopy = AllocVec(len + 1, MEMF_PUBLIC);
161 if (!patterncopy)
163 error = ERROR_NO_FREE_STORE;
164 goto done;
167 strcpy(patterncopy, pattern);
169 RemoveTrailingSlash(patterncopy);
171 patternstart = patterncopy;
173 patternpos = strchr(patterncopy, ':');
174 if (!patternpos)
176 comptype = COMPTYPE_UNKNOWN;
177 patternpos = patternstart;
178 patternend = patternstart;
180 else
182 comptype = COMPTYPE_NORMAL;
183 patternend = patternpos++;
184 compcount = 1;
189 for(;;)
191 c = *patternpos;
192 if (c == '/')
194 if (comptype == COMPTYPE_UNKNOWN)
196 comptype = COMPTYPE_NORMAL;
197 patternend = patternpos;
199 else if (comptype == COMPTYPE_NORMAL)
201 patternend = patternpos;
202 compcount++;
204 if (comptype == COMPTYPE_PATTERN)
206 patternend = patternpos;
207 break;
210 else if (c == '\0')
212 if (comptype == COMPTYPE_UNKNOWN)
214 comptype = COMPTYPE_NORMAL;
215 patternend = patternpos;
216 break;
218 if (comptype == COMPTYPE_NORMAL)
220 compcount++;
221 break;
223 patternend = patternpos;
224 break;
226 else if ((c == '#') ||
227 (c == '~') ||
228 (c == '[') ||
229 (c == ']') ||
230 (c == '?') ||
231 (c == '*') ||
232 (c == '(') ||
233 (c == ')') ||
234 (c == '|') ||
235 (c == '%'))
237 if (comptype == COMPTYPE_NORMAL)
239 break;
241 comptype = COMPTYPE_PATTERN;
244 patternpos++;
246 } /* for(;;) */
248 len = (LONG)(patternend - patternstart + 2);
249 if (comptype == COMPTYPE_PATTERN) len = len * 2 + 2;
251 ac = Match_AllocAChain(len, DOSBase);
252 if (!ac)
254 error = ERROR_NO_FREE_STORE;
255 goto done;
258 if (comptype == COMPTYPE_NORMAL)
260 if (*patternend == '\0')
262 strcpy(ac->an_String, patternstart);
263 } else {
264 c = patternend[1];
265 patternend[1] = '\0';
266 strcpy(ac->an_String, patternstart);
267 patternend[1] = c;
270 } /* if (comptype == COMPTYPE_NORMAL) */
271 else
273 if (*patternend == '\0')
275 i = ParsePatternNoCase(patternstart, ac->an_String, len);
277 else
279 c = patternend[1];
280 patternend[1] = '\0';
281 i = ParsePatternNoCase(patternstart, ac->an_String, len);
282 patternend[1] = c;
285 if (i == -1)
287 error = ERROR_BAD_TEMPLATE;
288 Match_FreeAChain(ac, DOSBase);ac = 0;
289 goto done;
292 if (i)
294 ac->an_Flags |= DDF_PatternBit;
295 AP->ap_Flags |= APF_ITSWILD;
298 } /* if (comptype == COMPTYPE_NORMAL) else ... */
300 RemoveTrailingSlash(ac->an_String);
302 if (!prevac)
304 baseac = ac;
306 else
308 prevac->an_Child = ac;
309 ac->an_Parent = prevac;
312 prevac = ac;
314 patternpos = patternend;
315 comptype = COMPTYPE_UNKNOWN;
316 patternstart = patternend = patternpos + 1;
317 compcount = 0;
319 } while (*patternpos++ != '\0');
321 done:
322 FreeVec(patterncopy);
324 if (!error)
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);
335 #endif
336 *retac = baseac;
338 else
340 AP->ap_Flags |= APF_NOMEMERR;
342 if (baseac)
344 #define nextac prevac /* to not have to add another variable */
346 ac = baseac;
347 while(ac)
349 nextac = ac->an_Child;
350 Match_FreeAChain(ac, DOSBase);
351 ac = nextac;
356 return error;
359 /****************************************************************************************/
361 static LONG Match_MakeResult(struct AnchorPath *AP, struct DosLibrary *DOSBase)
363 LONG error = 0;
365 AP->ap_Info = AP->ap_Current->an_Info;
366 if (AP->ap_Strlen)
368 AP->ap_Buf[0] = 0;
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))
373 error = IoErr();
375 } else {
376 error = IoErr();
380 return error;
383 /****************************************************************************************/
385 LONG My_MatchFirst(STRPTR pat, struct AnchorPath *AP)
387 struct AChain *ac;
388 LONG error;
390 AP->ap_Flags = 0;
391 AP->ap_Base = 0;
392 AP->ap_Current = 0;
394 error = BuildAChainList(pat, AP, &ac, DOSBase);
395 if (error == 0)
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);
405 SetIoErr(error);
407 return error;
410 /****************************************************************************************/
412 LONG My_MatchNext(struct AnchorPath *AP)
414 struct AChain *ac = AP->ap_Current;
415 BPTR origdir, old_current_lock;
416 LONG error = 0;
418 origdir = CurrentDir(0);
419 CurrentDir(origdir);
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;
446 ac = ac->an_Child;
447 AP->ap_Current = 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 */
463 for(;;)
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)
474 error = ERROR_BREAK;
475 goto done;
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
486 ** AChain is "in". !
489 if (ac->an_Parent)
491 CurrentDir(ac->an_Parent->an_Lock);
492 ac->an_Lock = Lock(ac->an_Parent->an_Info.fib_FileName, SHARED_LOCK);
494 if (!ac->an_Lock)
496 error = IoErr();
497 goto done;
501 #if !MATCHFUNCS_NO_DUPLOCK
502 else
504 ac->an_Lock = DupLock(origdir);
505 if (!ac->an_Lock)
507 error = IoErr();
508 goto done;
511 #else
513 ** If there was no ac->an_Parent then we are dealing with the
514 ** first AChain whose lock was already setup in BuildAChainList
516 #endif
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
524 ** ExNext
527 if (!Examine(ac->an_Lock, &ac->an_Info))
529 error = IoErr();
530 goto done;
532 ac->an_Flags |= DDF_ExaminedBit;
534 } /* if (ac->an_Flags & DDF_PatternBit) */
535 else
537 BPTR lock;
538 LONG success;
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 */
549 if (ac->an_Parent)
551 /* [2] */
553 must_go_back = TRUE;
555 else
557 /* if going back is not possible get error code and exit */
558 error = IoErr();
559 goto done;
562 } /* if (!(lock = Lock(ac->an_String, SHARED_LOCK))) */
563 else
565 /* The File/Direcory ac->an_String exists */
567 success = Examine(lock, &ac->an_Info);
568 UnLock(lock);
570 if (!success)
573 ** Examine()ing the file/directory did not
574 ** work, although the lock was successful!?.
575 ** Get error code and exit
578 error = IoErr();
579 goto done;
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))
599 /* [1] */
601 must_go_back = TRUE;
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)) */
616 else
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
623 ** one step
626 if (!(ac->an_Flags & DDF_PatternBit))
628 /* [4] */
630 must_go_back = TRUE;
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
637 ** was set
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;
656 } else {
657 /* Did not match. Go to top of "for(;;)" loop */
658 continue;
661 else
663 error = IoErr();
664 if (error != ERROR_NO_MORE_ENTRIES) goto done;
666 /* [3] */
668 must_go_back = TRUE;
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].
682 if (must_go_back)
684 /* Check if going back is possible at all */
686 if (!ac->an_Parent)
688 error = ERROR_NO_MORE_ENTRIES;
689 goto done;
692 /* Yep. It is possible. So let's cleanup the AChain. */
694 CurrentDir(ac->an_Parent->an_Lock);
696 UnLock(ac->an_Lock);
698 ac->an_Lock = BNULL;
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
710 ** was leaved.
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 */
721 break;
724 ac = AP->ap_Current;
726 } /* if (must_go_back) */
727 else
729 if (!ac->an_Child)
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
737 break;
740 ac = ac->an_Child;
741 AP->ap_Current = ac;
744 } /* for(;;) */
746 error = Match_MakeResult(AP, DOSBase);
748 done:
749 CurrentDir(origdir);
751 AP->ap_Flags &= ~APF_DODIR;
753 if (old_current_lock != AP->ap_Current->an_Lock)
755 AP->ap_Flags |= APF_DirChanged;
757 else
759 AP->ap_Flags &= ~APF_DirChanged;
762 SetIoErr(error);
764 return error;
768 /****************************************************************************************/
770 void My_MatchEnd(struct AnchorPath *AP)
772 struct AChain *ac = AP->ap_Base, *acnext;
774 if (ac)
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);
784 #endif
785 while(ac)
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!!!
795 if (ac->an_Lock
796 #if MATCHFUNCS_NO_DUPLOCK
797 && (ac != AP->ap_Base)
798 #endif
801 UnLock(ac->an_Lock);
804 Match_FreeAChain(ac, DOSBase);
806 ac = acnext;
810 AP->ap_Current = NULL;
811 AP->ap_Base = NULL;
814 /****************************************************************************************/
816 #define ARG_TEMPLATE "FILE/A,ALL/S"
817 #define ARG_FILE 0
818 #define ARG_ALL 1
819 #define NUM_ARGS 2
821 /****************************************************************************************/
823 static char s[300];
824 static char *filename;
825 static BOOL all;
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);
837 exit(0);
840 /****************************************************************************************/
842 static void doserror(void)
844 Fault(IoErr(), 0, s, 255);
845 cleanup(s);
848 /****************************************************************************************/
850 static void getarguments(void)
852 if (!(myargs = ReadArgs(ARG_TEMPLATE, args, 0)))
854 doserror();
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;
866 LONG error = 0;
868 AP = (struct AnchorPath *)((((IPTR)stackap) + 3) & ~3);
870 memset(AP, 0, sizeof(struct AnchorPath));
872 error = My_MatchFirst(pattern, AP);
874 if (error != 0)
876 printf("MatchFirst: error = %d\n", (int)error);
878 else
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);
894 while(error == 0)
896 if (AP->ap_Flags & APF_DIDDIR)
898 printf("DIDDIR: ");
899 } else {
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);
913 My_MatchEnd(AP);
917 /****************************************************************************************/
918 /****************************************************************************************/
920 int main(void)
922 getarguments();
923 my_matchme(filename, all);
924 cleanup(0);
925 return 0;
928 /****************************************************************************************/