JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / com / stevesoft / pat / RegexWriter.java
1 //
2 // This software is now distributed according to
3 // the Lesser Gnu Public License.  Please see
4 // http://www.gnu.org/copyleft/lesser.txt for
5 // the details.
6 //    -- Happy Computing!
7 //
8 package com.stevesoft.pat;
9
10 import java.io.IOException;
11 import java.io.Writer;
12
13 import com.stevesoft.pat.wrap.WriterWrap;
14
15 /**
16  * A basic extension of FilterWriter that uses Transformer to make replacements
17  * in data as it is written out. It attempts to transform a string whenever the
18  * End-of-Line (EOL) character is written (which is, by default, the carriage
19  * return '\n'). Only the transformed portion of the line is written out,
20  * allowing the RegexWriter to wait until a complete pattern is present before
21  * attempting to write out info. Until a pattern completes, data is stored in a
22  * StringBuffer -- which can be accessed through the length() and charAt()
23  * methods of this class.
24  * <p>
25  * Note a subtlety here -- while a Transformer normally matches at higher
26  * priority against the pattern added to it first, this will not necessarily be
27  * true when a multi-line match is in progress because one of the complete
28  * multi-line patterns may not be completely loaded in RegexWriter's buffer. For
29  * this reason, the Transformer class is equipped with a way to add a pattern
30  * and replacement rule in three pieces -- a beginning (once this matches,
31  * nothing else in the Transformer can match until the whole pattern matches),
32  * an ending (the whole pattern is a String formed by adding the beginning and
33  * ending), and a ReplaceRule.
34  * <p>
35  * An illustration of this is given in the this <a
36  * href="../test/trans.java">example.</a>
37  */
38 public class RegexWriter extends Writer
39 {
40   Replacer repr;
41
42   Writer w;
43
44   WriterWrap ww;
45
46   StringBuffer sb = new StringBuffer();
47
48   PartialBuffer wrap = new PartialBuffer(sb);
49
50   int pos, epos;
51
52   int interval = 128;
53
54   int bufferSize = 2 * 1024;
55
56   public RegexWriter(Transformer t, Writer w)
57   {
58     this.w = w;
59     ww = new WriterWrap(w);
60     repr = t.getReplacer();
61     repr.setBuffer(new StringBufferLike(ww));
62     repr.setSource(wrap);
63   }
64
65   public RegexWriter(Regex r, Writer w)
66   {
67     this.w = w;
68     ww = new WriterWrap(w);
69     repr = r.getReplacer();
70     repr.setBuffer(new StringBufferLike(ww));
71     repr.setSource(wrap);
72   }
73
74   char EOLchar = '\n';
75
76   /**
77    * This method no longer serves any purpose.
78    * 
79    * @deprecated
80    */
81   @Deprecated
82   public char getEOLchar()
83   {
84     return EOLchar;
85   }
86
87   /**
88    * This method no longer serves any purpose.
89    * 
90    * @deprecated
91    */
92   @Deprecated
93   public void setEOLchar(char c)
94   {
95     EOLchar = c;
96   }
97
98   int max_lines = 2;
99
100   /**
101    * This method no longer serves any purpose.
102    * 
103    * @deprecated
104    */
105   @Deprecated
106   public int getMaxLines()
107   {
108     return max_lines;
109   }
110
111   /**
112    * This method no longer serves any purpose.
113    * 
114    * @deprecated
115    */
116   @Deprecated
117   public void setMaxLines(int ml)
118   {
119     max_lines = ml;
120   }
121
122   void write() throws IOException
123   {
124     Regex rex = repr.getRegex();
125     int eposOld = epos;
126     if (rex.matchAtLike(wrap, epos) && !wrap.overRun)
127     {
128       while (pos < epos)
129       {
130         w.write(sb.charAt(pos++));
131       }
132       int to = rex.matchedTo();
133       repr.setPos(to);
134       repr.apply(rex, rex.getReplaceRule());
135       epos = pos = to;
136       if (epos == eposOld && epos < sb.length())
137       {
138         epos++;
139       }
140     }
141     else if (!wrap.overRun && epos < sb.length())
142     {
143       epos++;
144     }
145     while (pos < epos)
146     {
147       w.write(sb.charAt(pos++));
148     }
149     if (epos == sb.length())
150     {
151       sb.setLength(1);
152       pos = epos = 1;
153     }
154     else if (pos > bufferSize)
155     {
156       for (int i = bufferSize; i < sb.length(); i++)
157       {
158         sb.setCharAt(i - bufferSize, sb.charAt(i));
159       }
160       pos -= bufferSize;
161       epos -= bufferSize;
162       sb.setLength(sb.length() - bufferSize);
163     }
164   }
165
166   public void write(char[] ca, int b, int n) throws IOException
167   {
168     int m = b + n;
169     for (int i = b; i < m; i++)
170     {
171       sb.append(ca[i]);
172       if (sb.length() % interval == interval - 1)
173       {
174         wrap.overRun = false;
175         while (epos + interval < sb.length() && !wrap.overRun)
176         {
177           write();
178         }
179       }
180     }
181   }
182
183   public void flush() throws IOException
184   {
185   }
186
187   public void close() throws IOException
188   {
189     wrap.allowOverRun = false;
190     wrap.overRun = false;
191     while (epos < sb.length())
192     {
193       write();
194     }
195     write();
196     w.close();
197   }
198
199   /** The current size of the StringBuffer in use by RegexWriter. */
200   public int length()
201   {
202     return sb.length();
203   }
204
205   /** The character at location i in the StringBuffer. */
206   public char charAt(int i)
207   {
208     return sb.charAt(i);
209   }
210
211   /** Set the interval at which regex patterns are checked. */
212   public void setInterval(int i)
213   {
214     interval = i;
215   }
216
217   /** Get the interval at which regex matches are checked. */
218   public int getInterval()
219   {
220     return interval;
221   }
222
223   /** Get the buffer size. */
224   public int getBufferSize()
225   {
226     return bufferSize;
227   }
228
229   /** Set the buffer size. */
230   public void setBufferSize(int i)
231   {
232     bufferSize = i;
233   }
234 }