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