2010-01-20 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mcs / class / System / System.Text.RegularExpressions / BaseMachine.cs
1 //\r
2 // BaseMachine.cs\r
3 //\r
4 // Author:\r
5 // author:      Dan Lewis (dlewis@gmx.co.uk)\r
6 //              (c) 2002\r
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)\r
8 //\r
9 \r
10 //\r
11 // Permission is hereby granted, free of charge, to any person obtaining\r
12 // a copy of this software and associated documentation files (the\r
13 // "Software"), to deal in the Software without restriction, including\r
14 // without limitation the rights to use, copy, modify, merge, publish,\r
15 // distribute, sublicense, and/or sell copies of the Software, and to\r
16 // permit persons to whom the Software is furnished to do so, subject to\r
17 // the following conditions:\r
18 //\r
19 // The above copyright notice and this permission notice shall be\r
20 // included in all copies or substantial portions of the Software.\r
21 //\r
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
29 //\r
30 \r
31 using System;\r
32 using System.Collections;\r
33 using System.Collections.Specialized;\r
34 \r
35 namespace System.Text.RegularExpressions\r
36 {\r
37         abstract class BaseMachine : IMachine\r
38         {\r
39                 internal delegate void MatchAppendEvaluator (Match match, StringBuilder sb);\r
40 \r
41                 public virtual string Replace (Regex regex, string input, string replacement, int count, int startat)\r
42                 {\r
43                         ReplacementEvaluator ev = new ReplacementEvaluator (regex, replacement);\r
44                         if (regex.RightToLeft)\r
45                                 return RTLReplace (regex, input, new MatchEvaluator (ev.Evaluate), count, startat);\r
46                         else\r
47                                 return LTRReplace (regex, input, new MatchAppendEvaluator (ev.EvaluateAppend), count, startat, ev.NeedsGroupsOrCaptures);\r
48                 }\r
49 \r
50                 virtual public string [] Split (Regex regex, string input, int count, int startat)\r
51                 {\r
52                         ArrayList splits = new ArrayList ();\r
53                         if (count == 0)\r
54                                 count = Int32.MaxValue;\r
55 \r
56                         int ptr = startat;\r
57                         Match m = null;\r
58                         while (--count > 0) {\r
59                                 if (m != null)\r
60                                         m = m.NextMatch ();\r
61                                 else\r
62                                         m = regex.Match (input, ptr);\r
63 \r
64                                 if (!m.Success)\r
65                                         break;\r
66 \r
67                                 if (regex.RightToLeft)\r
68                                         splits.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));\r
69                                 else\r
70                                         splits.Add (input.Substring (ptr, m.Index - ptr));\r
71 \r
72                                 int gcount = m.Groups.Count;\r
73                                 for (int gindex = 1; gindex < gcount; gindex++) {\r
74                                         Group grp = m.Groups [gindex];\r
75                                         splits.Add (input.Substring (grp.Index, grp.Length));\r
76                                 }\r
77 \r
78                                 if (regex.RightToLeft)\r
79                                         ptr = m.Index;\r
80                                 else\r
81                                         ptr = m.Index + m.Length;\r
82 \r
83                         }\r
84 \r
85                         if (regex.RightToLeft && ptr >= 0)\r
86                                 splits.Add (input.Substring (0, ptr));\r
87                         if (!regex.RightToLeft && ptr <= input.Length)\r
88                                 splits.Add (input.Substring (ptr));\r
89 \r
90                         return (string []) splits.ToArray (typeof (string));\r
91                 }\r
92 \r
93                 virtual public Match Scan (Regex regex, string text, int start, int end)\r
94                 {\r
95                         throw new NotImplementedException ("Scan method must be implemented in derived classes");\r
96                 }\r
97 \r
98                 virtual public string Result (string replacement, Match match)\r
99                 {\r
100                         return ReplacementEvaluator.Evaluate (replacement, match);\r
101                 }\r
102 \r
103                 internal string LTRReplace (Regex regex, string input, MatchAppendEvaluator evaluator, int count, int startat) {\r
104                         return LTRReplace (regex, input, evaluator, count, startat, true);\r
105                 }\r
106 \r
107                 internal string LTRReplace (Regex regex, string input, MatchAppendEvaluator evaluator, int count, int startat, bool needs_groups_or_captures)\r
108                 {\r
109                         this.needs_groups_or_captures = needs_groups_or_captures;\r
110                         \r
111                         Match m = Scan (regex, input, startat, input.Length);\r
112                         if (!m.Success)\r
113                                 return input;\r
114 \r
115                         StringBuilder result = new StringBuilder (input.Length);\r
116                         int ptr = startat;\r
117                         int counter = count;\r
118 \r
119                         result.Append (input, 0, ptr);\r
120 \r
121                         do {\r
122                                 if (count != -1)\r
123                                         if (counter-- <= 0)\r
124                                                 break;\r
125                                 if (m.Index < ptr)\r
126                                         throw new SystemException ("how");\r
127                                 result.Append (input, ptr, m.Index - ptr);\r
128                                 evaluator (m, result);\r
129 \r
130                                 ptr = m.Index + m.Length;\r
131                                 m = m.NextMatch ();\r
132                         } while (m.Success);\r
133 \r
134                         result.Append (input, ptr, input.Length - ptr);\r
135 \r
136                         return result.ToString ();\r
137                 }\r
138 \r
139                 internal string RTLReplace (Regex regex, string input, MatchEvaluator evaluator, int count, int startat)\r
140                 {\r
141                         Match m = Scan (regex, input, startat, input.Length);\r
142                         if (!m.Success)\r
143                                 return input;\r
144 \r
145                         int ptr = startat;\r
146                         int counter = count;\r
147 #if NET_2_1\r
148                         var pieces = new System.Collections.Generic.List<string> ();\r
149 #else\r
150                         StringCollection pieces = new StringCollection ();\r
151 #endif\r
152                         \r
153                         pieces.Add (input.Substring (ptr));\r
154 \r
155                         do {\r
156                                 if (count != -1)\r
157                                         if (counter-- <= 0)\r
158                                                 break;\r
159                                 if (m.Index + m.Length > ptr)\r
160                                         throw new SystemException ("how");\r
161                                 pieces.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));\r
162                                 pieces.Add (evaluator (m));\r
163 \r
164                                 ptr = m.Index;\r
165                                 m = m.NextMatch ();\r
166                         } while (m.Success);\r
167 \r
168                         StringBuilder result = new StringBuilder ();\r
169 \r
170                         result.Append (input, 0, ptr);\r
171                         for (int i = pieces.Count; i > 0; )\r
172                                 result.Append (pieces [--i]);\r
173 \r
174                         pieces.Clear ();\r
175 \r
176                         return result.ToString ();\r
177                 }\r
178 \r
179                 // Specify whenever Match objects created by this machine need to be fully\r
180                 // built. If false, these can be omitted, avoiding some memory allocations and\r
181                 // processing time.\r
182                 protected bool needs_groups_or_captures = true; \r
183         }\r
184 }\r