Detabbed
[AROS.git] / rom / dos / match_misc.c
blob12c04ab6354db2e5d36046e91be2641744c58044
1 /*
2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Support functions for MatchFirst/MatchNext/MatchEnd
6 Lang: english
7 */
9 /****************************************************************************************/
11 #include <exec/memory.h>
12 #include <dos/dos.h>
13 #include <dos/dosextens.h>
14 #include <dos/dosasl.h>
15 #include <proto/dos.h>
16 #include <proto/exec.h>
18 #include "dos_intern.h"
19 #include <aros/debug.h>
21 #include <string.h>
23 /****************************************************************************************/
25 #define COMPTYPE_NORMAL 1
26 #define COMPTYPE_PATTERN 2
27 #define COMPTYPE_UNKNOWN 3
29 /****************************************************************************************/
31 struct AChain *Match_AllocAChain(LONG extrasize, struct DosLibrary *DOSBase)
33 return AllocVec(sizeof(struct AChain) + extrasize, MEMF_PUBLIC | MEMF_CLEAR);
36 /****************************************************************************************/
38 void Match_FreeAChain(struct AChain *ac, struct DosLibrary *DOSBase)
40 FreeVec(ac);
43 /****************************************************************************************/
45 static void RemoveTrailingSlash(STRPTR s)
47 LONG len = strlen(s);
49 if (len >= 2)
51 if ((s[len - 1] == '/') &&
52 ((s[len - 2] != '/') && (s[len - 2] != ':')))
54 s[len - 1] = '\0';
59 /**************************************************************************
61 The job of Match_BuildAChainList is to split the pattern string passed to
62 MatchFirst into path components. Most imporant rules (as found out after
63 hours of testing on Amiga):
65 - Each path component containing a pattern string is put into a single
66 AChain
67 - If there are several successive path components *without* pattern then
68 this are merged into one single AChain.
69 - No matter what: the last path component always gets into its own single
70 AChain.
72 Examples: [<???>] is one AChain
74 pictures [pictures]
75 pictures/#? [pictures} [#?]
76 work: [work:] []
77 work:pictures [work:} [pictures]
78 work:pictures/#? [work:pictures] [#?]
79 work:pictures/aros [work:pictures] [aros]
80 work:pictures/aros/games [work:pictures/aros] [games]
81 work:#?/aros/games [work:] [#?] [aros] [games}
82 work:#?/#?/aros/games/quake [work:} [#?] [#?] [aros/games] [quake]
84 **************************************************************************/
86 LONG Match_BuildAChainList(CONST_STRPTR pattern, struct AnchorPath *ap,
87 struct AChain **retac, struct DosLibrary *DOSBase)
89 struct AChain *baseac = 0, *prevac = 0, *ac;
90 STRPTR patterncopy = 0;
91 STRPTR patternstart, patternend, patternpos;
92 LONG len, error = 0;
93 WORD comptype = COMPTYPE_UNKNOWN;
94 WORD compcount = 0;
95 WORD i;
96 UBYTE c;
98 *retac = 0;
100 len = strlen(pattern);
102 patterncopy = AllocVec(len + 1, MEMF_PUBLIC);
103 if (!patterncopy)
105 error = ERROR_NO_FREE_STORE;
106 goto done;
109 strcpy(patterncopy, pattern);
111 RemoveTrailingSlash(patterncopy);
113 patternstart = patterncopy;
115 patternpos = strchr(patterncopy, ':');
116 if (!patternpos)
118 comptype = COMPTYPE_UNKNOWN;
119 patternpos = patternstart;
120 patternend = patternstart;
122 else
124 comptype = COMPTYPE_NORMAL;
125 patternend = patternpos++;
126 compcount = 1;
131 for(;;)
133 c = *patternpos;
134 if (c == '/')
136 if (comptype == COMPTYPE_UNKNOWN)
138 comptype = COMPTYPE_NORMAL;
139 patternend = patternpos;
141 else if (comptype == COMPTYPE_NORMAL)
143 patternend = patternpos;
144 compcount++;
146 if (comptype == COMPTYPE_PATTERN)
148 patternend = patternpos;
149 break;
152 else if (c == '\0')
154 if (comptype == COMPTYPE_UNKNOWN)
156 comptype = COMPTYPE_NORMAL;
157 patternend = patternpos;
158 break;
160 if (comptype == COMPTYPE_NORMAL)
162 compcount++;
163 break;
165 patternend = patternpos;
166 break;
168 else if ((c == '#') ||
169 (c == '~') ||
170 (c == '[') ||
171 (c == ']') ||
172 (c == '?') ||
173 (c == '*') ||
174 (c == '(') ||
175 (c == ')') ||
176 (c == '|') ||
177 (c == '%'))
179 if (comptype == COMPTYPE_NORMAL)
181 break;
183 comptype = COMPTYPE_PATTERN;
186 patternpos++;
188 } /* for(;;) */
190 len = (LONG)(patternend - patternstart + 2);
191 if (comptype == COMPTYPE_PATTERN) len = len * 2 + 2;
193 ac = Match_AllocAChain(len, DOSBase);
194 if (!ac)
196 error = ERROR_NO_FREE_STORE;
197 goto done;
200 if (comptype == COMPTYPE_NORMAL)
202 if (*patternend == '\0')
204 strcpy(ac->an_String, patternstart);
205 } else {
206 c = patternend[1];
207 patternend[1] = '\0';
208 strcpy(ac->an_String, patternstart);
209 patternend[1] = c;
212 } /* if (comptype == COMPTYPE_NORMAL) */
213 else
215 if (*patternend == '\0')
217 i = ParsePatternNoCase(patternstart, ac->an_String, len);
218 if (i == 0)
220 /* It is not a pattern, although we guessed it was one.
221 Do the strcpy, otherwise we have uppercase stuff in
222 ac->an_String because of ParsePatternNOCASE() */
223 strcpy(ac->an_String, patternstart);
226 else
228 c = patternend[1];
229 patternend[1] = '\0';
230 i = ParsePatternNoCase(patternstart, ac->an_String, len);
231 if (i == 0)
233 /* It is not a pattern, although we guessed it was one.
234 Do the strcpy, otherwise we have uppercase stuff in
235 ac->an_String because of ParsePatternNOCASE() */
236 strcpy(ac->an_String, patternstart);
238 patternend[1] = c;
241 if (i == -1)
243 error = ERROR_BAD_TEMPLATE;
244 Match_FreeAChain(ac, DOSBase);ac = 0;
245 goto done;
248 if (i)
250 ac->an_Flags |= DDF_PatternBit;
251 ap->ap_Flags |= APF_ITSWILD;
254 } /* if (comptype == COMPTYPE_NORMAL) else ... */
256 RemoveTrailingSlash(ac->an_String);
258 if (!prevac)
260 baseac = ac;
262 else
264 prevac->an_Child = ac;
265 ac->an_Parent = prevac;
268 prevac = ac;
270 patternpos = patternend;
271 comptype = COMPTYPE_UNKNOWN;
272 patternstart = patternend = patternpos + 1;
273 compcount = 0;
275 } while (*patternpos++ != '\0');
277 done:
278 if (patterncopy) FreeVec(patterncopy);
280 if (!error)
282 #if MATCHFUNCS_NO_DUPLOCK
284 * No DupLock() here, because then we would have to UnLock it in
285 * MatchEnd and we would not know any valid lock to which we could
286 * CurrentDir after, because we must make sure there is a valid
287 * CurrentDir after MatchEnd.
290 baseac->an_Lock = CurrentDir(0);
291 CurrentDir(baseac->an_Lock);
292 #endif
294 *retac = baseac;
296 else
298 ap->ap_Flags |= APF_NOMEMERR;
300 if (baseac)
302 #define nextac prevac /* to not have to add another variable */
304 ac = baseac;
305 while(ac)
307 nextac = ac->an_Child;
308 Match_FreeAChain(ac, DOSBase);
309 ac = nextac;
314 return error;}
316 /******************************************************************************/
318 LONG Match_MakeResult(struct AnchorPath *ap, struct DosLibrary *DOSBase)
320 #if 1
321 LONG error = 0;
323 ap->ap_Info = ap->ap_Current->an_Info;
324 if (ap->ap_Strlen)
326 struct AChain *ac;
328 ap->ap_Buf[0] = 0;
330 for(ac = ap->ap_Base; (ac && !error); ac = ac->an_Child)
332 if (!AddPart(ap->ap_Buf,
333 ((ac->an_Flags & DDF_PatternBit) ? ac->an_Info.fib_FileName : ac->an_String),
334 ap->ap_Strlen))
336 error = IoErr();
341 #else
342 LONG error = 0;
344 ap->ap_Info = ap->ap_Current->an_Info;
345 if (ap->ap_Strlen)
347 ap->ap_Buf[0] = 0;
348 if (NameFromLock(ap->ap_Current->an_Lock, ap->ap_Buf, ap->ap_Strlen))
350 if (!AddPart(ap->ap_Buf, ap->ap_Current->an_Info.fib_FileName, ap->ap_Strlen))
352 error = IoErr();
354 } else {
355 error = IoErr();
358 #endif
360 return error;
363 /******************************************************************************/