Merge branch 'msbuilddll2'
[mono.git] / mcs / class / corlib / System.IO / SearchPattern.cs
1 //\r
2 // System.IO.SearchPattern.cs: Filename glob support.\r
3 //\r
4 // Author:\r
5 //   Dan Lewis (dihlewis@yahoo.co.uk)\r
6 //\r
7 // (C) 2002\r
8 //\r
9 \r
10 //\r
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)\r
12 //\r
13 // Permission is hereby granted, free of charge, to any person obtaining\r
14 // a copy of this software and associated documentation files (the\r
15 // "Software"), to deal in the Software without restriction, including\r
16 // without limitation the rights to use, copy, modify, merge, publish,\r
17 // distribute, sublicense, and/or sell copies of the Software, and to\r
18 // permit persons to whom the Software is furnished to do so, subject to\r
19 // the following conditions:\r
20 // \r
21 // The above copyright notice and this permission notice shall be\r
22 // included in all copies or substantial portions of the Software.\r
23 // \r
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
31 //\r
32 \r
33 using System;\r
34 \r
35 namespace System.IO {\r
36 \r
37         // FIXME: there's a complication with this algorithm under windows.\r
38         // the pattern '*.*' matches all files (i think . matches the extension),\r
39         // whereas under UNIX it should only match files containing the '.' character.\r
40 \r
41         class SearchPattern\r
42         {\r
43 /*              \r
44                 public SearchPattern (string pattern) : this (pattern, false) { }\r
45 \r
46                 public SearchPattern (string pattern, bool ignore)\r
47                 {\r
48                         this.ignore = ignore;\r
49                         Compile (pattern);\r
50                 }\r
51 \r
52                 public bool IsMatch (string text)\r
53                 {\r
54                         return Match (ops, text, 0);\r
55                 }\r
56 \r
57                 // private\r
58 \r
59                 private Op ops;         // the compiled pattern\r
60                 private bool ignore;    // ignore case\r
61 \r
62                 private void Compile (string pattern)\r
63                 {\r
64                         if (pattern == null || pattern.IndexOfAny (InvalidChars) >= 0)\r
65                                 throw new ArgumentException ("Invalid search pattern.");\r
66 \r
67                         if (pattern == "*") {   // common case\r
68                                 ops = new Op (OpCode.True);\r
69                                 return;\r
70                         }\r
71 \r
72                         ops = null;\r
73 \r
74                         int ptr = 0;\r
75                         Op last_op = null;\r
76                         while (ptr < pattern.Length) {\r
77                                 Op op;\r
78                         \r
79                                 switch (pattern [ptr]) {\r
80                                 case '?':\r
81                                         op = new Op (OpCode.AnyChar);\r
82                                         ++ ptr;\r
83                                         break;\r
84 \r
85                                 case '*':\r
86                                         op = new Op (OpCode.AnyString);\r
87                                         ++ ptr;\r
88                                         break;\r
89                                         \r
90                                 default:\r
91                                         op = new Op (OpCode.ExactString);\r
92                                         int end = pattern.IndexOfAny (WildcardChars, ptr);\r
93                                         if (end < 0)\r
94                                                 end = pattern.Length;\r
95 \r
96                                         op.Argument = pattern.Substring (ptr, end - ptr);\r
97                                         if (ignore)\r
98                                                 op.Argument = op.Argument.ToLowerInvariant ();\r
99 \r
100                                         ptr = end;\r
101                                         break;\r
102                                 }\r
103 \r
104                                 if (last_op == null)\r
105                                         ops = op;\r
106                                 else\r
107                                         last_op.Next = op;\r
108 \r
109                                 last_op = op;\r
110                         }\r
111 \r
112                         if (last_op == null)\r
113                                 ops = new Op (OpCode.End);\r
114                         else\r
115                                 last_op.Next = new Op (OpCode.End);\r
116                 }\r
117 \r
118                 private bool Match (Op op, string text, int ptr)\r
119                 {\r
120                         while (op != null) {\r
121                                 switch (op.Code) {\r
122                                 case OpCode.True:\r
123                                         return true;\r
124 \r
125                                 case OpCode.End:\r
126                                         if (ptr == text.Length)\r
127                                                 return true;\r
128 \r
129                                         return false;\r
130                                 \r
131                                 case OpCode.ExactString:\r
132                                         int length = op.Argument.Length;\r
133                                         if (ptr + length > text.Length)\r
134                                                 return false;\r
135 \r
136                                         string str = text.Substring (ptr, length);\r
137                                         if (ignore)\r
138                                                 str = str.ToLowerInvariant ();\r
139 \r
140                                         if (str != op.Argument)\r
141                                                 return false;\r
142 \r
143                                         ptr += length;\r
144                                         break;\r
145 \r
146                                 case OpCode.AnyChar:\r
147                                         if (++ ptr > text.Length)\r
148                                                 return false;\r
149                                         break;\r
150 \r
151                                 case OpCode.AnyString:\r
152                                         while (ptr <= text.Length) {\r
153                                                 if (Match (op.Next, text, ptr))\r
154                                                         return true;\r
155 \r
156                                                 ++ ptr;\r
157                                         }\r
158 \r
159                                         return false;\r
160                                 }\r
161 \r
162                                 op = op.Next;\r
163                         }\r
164 \r
165                         return true;\r
166                 }\r
167 \r
168                 // private static\r
169 */\r
170                 internal static readonly char [] WildcardChars = { '*', '?' };\r
171 /*              \r
172                 internal static readonly char [] InvalidChars = { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };\r
173 \r
174                 private class Op {\r
175                         public Op (OpCode code)\r
176                         {\r
177                                 this.Code = code;\r
178                                 this.Argument = null;\r
179                                 this.Next = null;\r
180                         }\r
181                 \r
182                         public OpCode Code;\r
183                         public string Argument;\r
184                         public Op Next;\r
185                 }\r
186 \r
187                 private enum OpCode {\r
188                         ExactString,            // literal\r
189                         AnyChar,                // ?\r
190                         AnyString,              // *\r
191                         End,                    // end of pattern\r
192                         True                    // always succeeds\r
193                 };\r
194 */\r
195         }\r
196 }\r