Fixed use of negative indices when first directory entry has no long name.
[tangerine.git] / test / matchtest.c
blobc2a8da154cfcf473aca7afd70c45dee211ac96fe
1 /* Test of the DOS functions MatchFirst MatchNext and MatchEnd.
2 */
4 #include <proto/dos.h>
5 #include <proto/exec.h>
6 #include <dos/dos.h>
7 #include <dos/dosasl.h>
8 #include <exec/types.h>
9 #include <exec/memory.h>
11 #include <stdio.h>
12 #include <string.h>
15 /*
16 Uncomment the following defines and function prototypes
17 if you want to use the code for the Match*-functions that
18 is in this file.
22 #undef MatchFirst
23 #undef MatchNext
24 #undef MatchEnd
25 #define MatchFirst MyMatchFirst
26 #define MatchNext MyMatchNext
27 #define MatchEnd MyMatchEnd
28 LONG MyMatchFirst(STRPTR pat, struct AnchorPath * AP);
29 LONG MyMatchNext(struct AnchorPath *AP);
30 void MyMatchEnd(struct AnchorPath *AP);
33 BOOL writeFullPath(struct AnchorPath *AP);
35 int main (void)
37 BOOL error;
38 int strlength=160;
39 struct AnchorPath * AP = AllocVec(sizeof(struct AnchorPath) + strlength,MEMF_CLEAR);
40 char * Pattern = AllocVec(80,MEMF_ANY);
42 //dirlock = Lock("sys:",ACCESS_READ);
43 //oldlock = CurrentDir(dirlock);
45 AP->ap_BreakBits = SIGBREAKF_CTRL_C;
46 AP->ap_Flags = 0;//APF_DODIR;
47 AP->ap_Strlen = strlength;
49 printf("Give me a pattern to serach for: ");
50 /* the following line breaks AROS in MatchEnd() when calling FreeVec()
51 the second time the program is run. I have no idea why, though. */
52 scanf("%s",Pattern);
53 printf("Pattern to search for: %s\n",Pattern);
55 for(error = MatchFirst(Pattern,AP); error == 0;
56 error = MatchNext(AP))
58 if (AP->ap_Flags & APF_DIDDIR)
60 AP->ap_Flags &= ~APF_DIDDIR;
61 printf(" leaving \033[32m%s\033[39m\n",AP->ap_Buf);
63 else /* if dir then enter it! */
65 if (AP->ap_Info.fib_DirEntryType >= 0)
67 AP->ap_Flags |=APF_DODIR;
68 printf("entering \033[33m%s\033[39m\n",AP->ap_Buf);
70 else
72 //BPTR fl = CurrentDir(AP->ap_Current->an_Lock);
73 //(void)CurrentDir(fl);
75 printf(" %s\n",AP->ap_Buf);
79 printf("error = %i \n",error);
80 MatchEnd(AP);
81 FreeVec(AP);
82 FreeVec(Pattern);
83 //CurrentDir(oldlock);
85 //UnLock(dirlock);
87 return 0;
90 #undef MatchFirst
91 #undef MatchNext
92 #undef MatchEnd
95 LONG MyMatchFirst(STRPTR pat, struct AnchorPath * AP)
97 struct AChain * AC;
98 struct AChain * AC_Prev = NULL;
99 LONG PatLength;
100 STRPTR ParsedPattern;
101 BPTR firstlock;
103 if (!pat)
104 return FALSE;
106 PatLength = 2*strlen(pat)+2;
108 ParsedPattern = AllocMem(PatLength, MEMF_ANY);
109 if (NULL != ParsedPattern)
111 LONG PatStart = 0;
112 LONG PatEnd = 0;
113 BOOL AllDone = FALSE;
114 LONG index;
115 BOOL success = FALSE;
116 /* put the preparsed string to some memory */
117 /* If there are any wildcards then leave info */
118 if (1 == ParsePatternNoCase(pat, ParsedPattern, PatLength))
119 AP->ap_Flags = (BYTE)APF_ITSWILD;
121 /* First I search for the very first ':'. If a '/' comes along
122 before that I quit. The string before and including the ':'
123 is assumed to be an assigned director, for example 'libs:'.
124 So I will start looking for the pattern in that directory.
126 while (TRUE)
128 if (ParsedPattern[PatEnd] == ':')
130 success = TRUE;
131 break;
133 else
135 if ( ParsedPattern[PatEnd] == '/' ||
136 ParsedPattern[PatEnd] == '\0' ||
137 (ParsedPattern[PatEnd] & 0x80) != 0
138 /* a token or nonprintable letter */)
140 PatEnd = 0;
141 break;
144 PatEnd++;
147 /* Only if success == TRUE an assigned dir was found. */
148 if (TRUE == success)
150 /* try to create a lock to that assigned dir. */
151 char Remember = ParsedPattern[PatEnd+1];
152 PatEnd++;
153 ParsedPattern[PatEnd] = '\0';
155 firstlock = Lock(ParsedPattern, ACCESS_READ);
156 /* check whether an error occurred */
157 if (NULL == firstlock)
159 FreeMem(ParsedPattern, PatLength);
160 return ERROR_DIR_NOT_FOUND; /* hope that's the right one... */
163 /* I have the correct lock. */
164 ParsedPattern[PatEnd] = Remember;
165 PatStart=PatEnd;
167 else
169 /* Create a lock to the current dir. */
170 firstlock = CurrentDir(NULL);
171 firstlock = DupLock(firstlock);
172 (void)CurrentDir(firstlock);
175 /* Build the Anchor Chain. For every subdirector I allocate
176 a AChain structure and link them all together */
177 while (FALSE == AllDone)
182 Search for the next '/' in the pattern and everything behind
183 the previous '/' and before this '/' will go to an_String
185 while (TRUE)
187 if (ParsedPattern[PatEnd] == '\0')
189 AllDone = TRUE;
190 PatEnd--;
191 break;
193 if (ParsedPattern[PatEnd] == '/')
195 PatEnd--;
196 break;
198 PatEnd++;
201 AC = AllocMem(sizeof(struct AChain)+(PatEnd-PatStart+2), MEMF_CLEAR);
202 if (NULL == AC)
204 /* not so bad if this was not the very first AC. */
205 if (NULL == AP->ap_Base)
207 /* oops, it was the very first one. I really cannot do anything for
208 you. - sorry */
209 FreeMem(ParsedPattern, PatLength);
210 return ERROR_NO_FREE_STORE;
213 /* let me out of here. I will at least try to do something for you.
214 I can check the first few subdirs but that's gonna be it.
216 AP->ap_Flags |= APF_NOMEMERR;
217 break;
220 if (NULL == AP->ap_Base)
222 AP->ap_Base = AC;
223 AP->ap_Current = AC;
226 if (NULL != AC_Prev)
228 AC_Prev->an_Child = AC;
230 AC->an_Parent = AC_Prev;
231 AC_Prev = AC;
233 /* copy the part of the pattern to the end of the AChain. */
234 index = 0;
235 while (PatStart <= PatEnd)
237 AC->an_String[index] = ParsedPattern[PatStart];
238 index++;
239 PatStart++;
241 /* Put PatStart and PetEnd behind the '/' that was found. */
242 PatStart = PatEnd + 2;
243 PatEnd += 2;
245 the trailing '\0' is there automatically as I allocated enough store
246 with MEMF_CLEAR
249 } /* while () */
251 /* The AnchorChain to work with is the very first one. */
252 AC = AP->ap_Base;
253 AC->an_Lock = firstlock;
255 /* look for the first file that matches the given pattern */
256 success = Examine(AC->an_Lock, &AC->an_Info);
257 success = ExNext (AC->an_Lock, &AC->an_Info);
258 while (DOSTRUE == success &&
259 DOSFALSE == MatchPatternNoCase(AC->an_String,
260 AC->an_Info.fib_FileName))
262 /* I still haven't found what I've been looking for ... */
263 success = ExNext(AC->an_Lock, &AC->an_Info);
266 if (DOSFALSE == success)
268 return ERROR_NO_MORE_ENTRIES;
271 /* Hooray! A matching file was found. Also show the data in AP */
272 CopyMem(&AC->an_Info, &AP->ap_Info, sizeof(struct FileInfoBlock));
273 if (0 != AP->ap_Strlen)
275 if (FALSE == writeFullPath(AP))
276 return ERROR_BUFFER_OVERFLOW;
278 return 0;
281 else
283 return ERROR_NO_FREE_STORE;
286 return 0;
290 LONG MyMatchNext(struct AnchorPath * AP)
292 /* If the user says I am supposed to enter the directory then I first check
293 whether it is a directory... */
294 struct AChain * AC = AP->ap_Current;
295 BOOL success;
296 if (0 != (AP->ap_Flags & APF_DODIR ))
298 if (AC->an_Info.fib_DirEntryType >= 0 /* &&
299 AC->an_Info.fib_DirEntryType != ST_SOFTLINK */)
301 /* Ok, it seems to be a directory so I will enter it. */
302 /* See whether there's a AnchorChain for that dir... */
303 if (NULL != AC->an_Child)
305 /* Ok, we're all set. */
306 /* Lock the director by it's name. */
307 AP->ap_Current = AC->an_Child;
308 AC->an_Child->an_Lock = Lock(AC->an_Info.fib_FileName, ACCESS_READ);
309 AC = AC->an_Child;
310 Examine(AC->an_Lock, &AC->an_Info);
314 AP->ap_Flags &= ~(BYTE)(APF_DODIR|APF_DIDDIR);
316 /* AC points to the current AnchorChain */
317 while (TRUE)
319 success = ExNext (AC->an_Lock, &AC->an_Info);
320 while (DOSTRUE == success &&
321 DOSFALSE == MatchPatternNoCase(AC->an_String,
322 AC->an_Info.fib_FileName))
324 success = ExNext(AC->an_Lock, &AC->an_Info);
327 if (DOSFALSE == success)
329 /* No more entries in this dir that match. So I might have to
330 step back one directory. Unlock the current dir first,
331 !!!!!???? but only if it is not the one from where I started
332 Otherwise AROS crashes...
335 if (NULL != AC->an_Parent)
336 UnLock(AC->an_Lock);
339 AC->an_Lock = NULL;
340 /* Are there any previous directories??? */
341 if (NULL != AC->an_Parent)
343 /* Step back to this directory and go on searching here */
344 AC = AC->an_Parent;
345 AP->ap_Current = AC;
346 CurrentDir(AC->an_Lock);
347 /* I show this dir again as I come back from searching it */
348 CopyMem(&AC->an_Info, &AP->ap_Info, sizeof(struct FileInfoBlock));
349 AP->ap_Flags |= APF_DIDDIR;
350 if (0 != AP->ap_Strlen)
352 if (FALSE == writeFullPath(AP))
353 return ERROR_BUFFER_OVERFLOW;
355 return 0;
357 else
359 /* No previous directory, so I am done here... */
360 return ERROR_NO_MORE_ENTRIES;
363 else
365 /* Alright, I found a match... */
366 CopyMem(&AC->an_Info, &AP->ap_Info, sizeof(struct FileInfoBlock));
367 if (0 != AP->ap_Strlen)
369 if (FALSE == writeFullPath(AP))
370 return ERROR_BUFFER_OVERFLOW;
372 return 0;
374 } /* while (TRUE) */
375 return 0;
378 void MyMatchEnd(struct AnchorPath * AP)
380 /* Free the AChain and unlock all locks that are still there */
381 struct AChain * AC = AP->ap_Current;
382 struct AChain * AC_tmp;
383 /* Unlock everything */
384 if (NULL == AC)
386 while (AC != AP->ap_Base)
388 UnLock(AC->an_Lock);
389 AC = AC->an_Parent;
391 /* AC points to the very first AChain obj. in the list */
393 /* Free the AChain List */
394 while (NULL != AC)
396 AC_tmp = AC->an_Child;
397 FreeVec(AC);
398 AC = AC_tmp;
400 /* Cleanup AP */
401 AP->ap_Base = NULL;
402 AP->ap_Current = NULL;
405 BOOL writeFullPath(struct AnchorPath * AP)
407 struct AChain * AC = AP->ap_Base;
408 BOOL end = FALSE;
409 char * LastPos = (char *)&AP->ap_Buf;
410 int copied = 0;
412 while (FALSE == end)
414 int len = strlen(AC->an_Info.fib_FileName);
415 if (copied+len > AP->ap_Strlen)
417 return FALSE;
419 strcpy(&LastPos[copied], AC->an_Info.fib_FileName);
420 copied += len;
422 if (AC != AP->ap_Current)
424 /* also add a '/' */
425 if (copied+1 > AP->ap_Strlen)
427 return FALSE;
429 LastPos[copied]='/';
430 copied++;
432 else
434 if (copied+1 > AP->ap_Strlen)
436 return FALSE;
438 LastPos[copied]='\0';
439 end = TRUE;
442 AC = AC->an_Child;
444 return TRUE;