JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / com / stevesoft / pat / parsePerl.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 /**
11  * This class provides a method for parsing the "s/.../.../" constructs of
12  * Regex.perlCode.
13  * 
14  * @see Regex#perlCode
15  */
16 class parsePerl
17 {
18   final static char close(char c)
19   {
20     // This switch statement does not behave
21     // properly when compiled with jdk1.1.5
22     // and the -O flag.
23     /*
24      * switch(c) { case '[': return ']'; case '(': return ')'; case '{': return
25      * '}'; } return c;
26      */
27     if (c == '<')
28     {
29       return '>';
30     }
31     if (c == '[')
32     {
33       return ']';
34     }
35     if (c == '(')
36     {
37       return ')';
38     }
39     if (c == '{')
40     {
41       return '}';
42     }
43     return c;
44   }
45
46   final public static String codify(String s, boolean keepbs)
47   {
48     return codify(s, 0, s.length(), keepbs);
49   }
50
51   final public static String codify(String s, int i0, int iN,
52           boolean keepbs)
53   {
54     StringBuffer sb = new StringBuffer();
55     boolean ucmode = false, lcmode = false, litmode = false;
56     boolean uc1 = false, lc1 = false;
57     boolean modified = false;
58     for (int i = i0; i < iN; i++)
59     {
60       char c = s.charAt(i);
61       boolean mf = true, app = true;
62       if (c == '\\')
63       {
64         app = false;
65         i++;
66         if (i < s.length())
67         {
68           char c2 = s.charAt(i);
69           switch (c2)
70           {
71           case 'Q':
72             litmode = true;
73             break;
74           case 'U':
75             ucmode = true;
76             break;
77           case 'L':
78             lcmode = true;
79             break;
80           case 'u':
81             uc1 = true;
82             break;
83           case 'l':
84             lc1 = true;
85             break;
86           case 'E':
87             uc1 = lc1 = ucmode = lcmode = litmode = false;
88             break;
89           default:
90             if (keepbs)
91             {
92               sb.append('\\');
93             }
94             c = c2;
95             if (keepbs)
96             {
97               mf = false;
98             }
99             app = true;
100             break;
101           }
102           modified |= mf;
103         }
104       }
105       if (app)
106       {
107         if (lc1)
108         {
109           c = lc(c);
110           lc1 = false;
111         }
112         else if (uc1)
113         {
114           c = uc(c);
115           uc1 = false;
116         }
117         else if (ucmode)
118         {
119           c = uc(c);
120         }
121         else if (lcmode)
122         {
123           c = lc(c);
124         }
125         if (litmode && needbs(c))
126         {
127           sb.append('\\');
128         }
129         sb.append(c);
130       }
131     }
132     return modified ? sb.toString() : s;
133   }
134
135   final static char uc(char c)
136   {
137     return CaseMgr.toUpperCase(c);
138   }
139
140   final static char lc(char c)
141   {
142     return CaseMgr.toLowerCase(c);
143   }
144
145   final static boolean needbs(char c)
146   {
147     if (c >= 'a' && c <= 'z')
148     {
149       return false;
150     }
151     if (c >= 'A' && c <= 'Z')
152     {
153       return false;
154     }
155     if (c >= '0' && c <= '9')
156     {
157       return false;
158     }
159     if (c == '_')
160     {
161       return false;
162     }
163     return true;
164   }
165
166   final static Regex parse(String s)
167   {
168     boolean igncase = false, optim = false, gFlag = false;
169     boolean sFlag = false, mFlag = false, xFlag = false;
170
171     StringBuffer s1 = new StringBuffer();
172     StringBuffer s2 = new StringBuffer();
173     int i = 0, count = 0;
174     char mode, delim = '/', cdelim = '/';
175     if (s.length() >= 3 && s.charAt(0) == 's')
176     {
177       mode = 's';
178       delim = s.charAt(1);
179       cdelim = close(delim);
180       i = 2;
181     }
182     else if (s.length() >= 2 && s.charAt(0) == 'm')
183     {
184       mode = 'm';
185       delim = s.charAt(1);
186       cdelim = close(delim);
187       i = 2;
188     }
189     else if (s.length() >= 1 && s.charAt(0) == '/')
190     {
191       mode = 'm';
192       i = 1;
193     }
194     else
195     {
196       try
197       {
198         RegSyntaxError.endItAll("Regex.perlCode should be of the "
199                 + "form s/// or m// or //");
200       } catch (RegSyntax rs)
201       {
202       }
203       return null;
204     }
205     for (; i < s.length(); i++)
206     {
207       if (s.charAt(i) == '\\')
208       {
209         s1.append('\\');
210         i++;
211       }
212       else if (s.charAt(i) == cdelim && count == 0)
213       {
214         i++;
215         break;
216       }
217       else if (s.charAt(i) == delim && cdelim != delim)
218       {
219         count++;
220       }
221       else if (s.charAt(i) == cdelim && cdelim != delim)
222       {
223         count--;
224       }
225       s1.append(s.charAt(i));
226     }
227     if (mode == 's' && cdelim != delim)
228     {
229       while (i < s.length() && Prop.isWhite(s.charAt(i)))
230       {
231         i++;
232       }
233       if (i >= s.length())
234       {
235         try
236         {
237           RegSyntaxError.endItAll("" + mode + delim + " needs " + cdelim);
238         } catch (RegSyntax rs)
239         {
240         }
241         return null;
242       }
243       cdelim = close(delim = s.charAt(i));
244       i++;
245     }
246     count = 0;
247     if (mode == 's')
248     {
249       for (; i < s.length(); i++)
250       {
251         if (s.charAt(i) == '\\')
252         {
253           s2.append('\\');
254           i++;
255         }
256         else if (s.charAt(i) == cdelim && count == 0)
257         {
258           i++;
259           break;
260         }
261         else if (s.charAt(i) == delim && cdelim != delim)
262         {
263           count++;
264         }
265         else if (s.charAt(i) == cdelim && cdelim != delim)
266         {
267           count--;
268         }
269         s2.append(s.charAt(i));
270       }
271     }
272     for (; i < s.length(); i++)
273     {
274       char c = s.charAt(i);
275       switch (c)
276       {
277       case 'x':
278         xFlag = true;
279         break;
280       case 'i':
281         igncase = true;
282         break;
283       case 'o':
284         optim = true;
285         break;
286       case 's':
287         sFlag = true;
288         break;
289       case 'm':
290         mFlag = true;
291         break;
292       case 'g':
293         gFlag = true;
294         break;
295       default:
296
297         // syntax error!
298         try
299         {
300           RegSyntaxError.endItAll("Illegal flag to pattern: " + c);
301         } catch (RegSyntax rs)
302         {
303         }
304         return null;
305       }
306     }
307     Regex r = new Regex();
308     try
309     {
310       String pat = s1.toString(), reprul = s2.toString();
311       if (xFlag)
312       {
313         pat = strip(pat);
314         reprul = strip(reprul);
315       }
316       r.compile(pat);
317       r.ignoreCase |= igncase;
318       r.gFlag |= gFlag;
319       r.sFlag |= sFlag;
320       r.mFlag |= mFlag;
321       if (optim)
322       {
323         r.optimize();
324       }
325       if (delim == '\'')
326       {
327         r.setReplaceRule(new StringRule(reprul));
328       }
329       else
330       {
331         r.setReplaceRule(ReplaceRule.perlCode(reprul));
332       }
333     } catch (RegSyntax rs)
334     {
335       r = null;
336     }
337     return r;
338   }
339
340   static String strip(String s)
341   {
342     StringBuffer sb = new StringBuffer();
343     for (int i = 0; i < s.length(); i++)
344     {
345       char c = s.charAt(i);
346       if (Prop.isWhite(c))
347       {
348         ;
349       }
350       else if (c == '#')
351       {
352         i++;
353         while (i < s.length())
354         {
355           if (s.charAt(i) == '\n')
356           {
357             break;
358           }
359           i++;
360         }
361       }
362       else if (c == '\\')
363       {
364         sb.append(c);
365         sb.append(s.charAt(++i));
366       }
367       else
368       {
369         sb.append(c);
370       }
371     }
372     return sb.toString();
373   }
374 }