Merge branch 'master' of git://github.com/mono/mono
[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                                         if (grp.Length > 0)\r
76                                                 splits.Add (input.Substring (grp.Index, grp.Length));\r
77                                 }\r
78 \r
79                                 if (regex.RightToLeft)\r
80                                         ptr = m.Index;\r
81                                 else\r
82                                         ptr = m.Index + m.Length;\r
83 \r
84                         }\r
85 \r
86                         if (regex.RightToLeft && ptr >= 0)\r
87                                 splits.Add (input.Substring (0, ptr));\r
88                         if (!regex.RightToLeft && ptr <= input.Length)\r
89                                 splits.Add (input.Substring (ptr));\r
90 \r
91                         return (string []) splits.ToArray (typeof (string));\r
92                 }\r
93 \r
94                 virtual public Match Scan (Regex regex, string text, int start, int end)\r
95                 {\r
96                         throw new NotImplementedException ("Scan method must be implemented in derived classes");\r
97                 }\r
98 \r
99                 virtual public string Result (string replacement, Match match)\r
100                 {\r
101                         return ReplacementEvaluator.Evaluate (replacement, match);\r
102                 }\r
103 \r
104                 internal string LTRReplace (Regex regex, string input, MatchAppendEvaluator evaluator, int count, int startat) {\r
105                         return LTRReplace (regex, input, evaluator, count, startat, true);\r
106                 }\r
107 \r
108                 internal string LTRReplace (Regex regex, string input, MatchAppendEvaluator evaluator, int count, int startat, bool needs_groups_or_captures)\r
109                 {\r
110                         this.needs_groups_or_captures = needs_groups_or_captures;\r
111                         \r
112                         Match m = Scan (regex, input, startat, input.Length);\r
113                         if (!m.Success)\r
114                                 return input;\r
115 \r
116                         StringBuilder result = new StringBuilder (input.Length);\r
117                         int ptr = startat;\r
118                         int counter = count;\r
119 \r
120                         result.Append (input, 0, ptr);\r
121 \r
122                         do {\r
123                                 if (count != -1)\r
124                                         if (counter-- <= 0)\r
125                                                 break;\r
126                                 if (m.Index < ptr)\r
127                                         throw new SystemException ("how");\r
128                                 result.Append (input, ptr, m.Index - ptr);\r
129                                 evaluator (m, result);\r
130 \r
131                                 ptr = m.Index + m.Length;\r
132                                 m = m.NextMatch ();\r
133                         } while (m.Success);\r
134 \r
135                         result.Append (input, ptr, input.Length - ptr);\r
136 \r
137                         return result.ToString ();\r
138                 }\r
139 \r
140                 internal string RTLReplace (Regex regex, string input, MatchEvaluator evaluator, int count, int startat)\r
141                 {\r
142                         Match m = Scan (regex, input, startat, input.Length);\r
143                         if (!m.Success)\r
144                                 return input;\r
145 \r
146                         int ptr = startat;\r
147                         int counter = count;\r
148 #if NET_2_1\r
149                         var pieces = new System.Collections.Generic.List<string> ();\r
150 #else\r
151                         StringCollection pieces = new StringCollection ();\r
152 #endif\r
153                         \r
154                         pieces.Add (input.Substring (ptr));\r
155 \r
156                         do {\r
157                                 if (count != -1)\r
158                                         if (counter-- <= 0)\r
159                                                 break;\r
160                                 if (m.Index + m.Length > ptr)\r
161                                         throw new SystemException ("how");\r
162                                 pieces.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));\r
163                                 pieces.Add (evaluator (m));\r
164 \r
165                                 ptr = m.Index;\r
166                                 m = m.NextMatch ();\r
167                         } while (m.Success);\r
168 \r
169                         StringBuilder result = new StringBuilder ();\r
170 \r
171                         result.Append (input, 0, ptr);\r
172                         for (int i = pieces.Count; i > 0; )\r
173                                 result.Append (pieces [--i]);\r
174 \r
175                         pieces.Clear ();\r
176 \r
177                         return result.ToString ();\r
178                 }\r
179 \r
180                 // Specify whenever Match objects created by this machine need to be fully\r
181                 // built. If false, these can be omitted, avoiding some memory allocations and\r
182                 // processing time.\r
183                 protected bool needs_groups_or_captures = true; \r
184         }\r
185 }\r