5cdbabeb2ec353242387675931e599c4e0b7e8e2
[jalview.git] / src / com / stevesoft / pat / parsePerl.java
1 //\r
2 // This software is now distributed according to\r
3 // the Lesser Gnu Public License.  Please see\r
4 // http://www.gnu.org/copyleft/lesser.txt for\r
5 // the details.\r
6 //    -- Happy Computing!\r
7 //\r
8 package com.stevesoft.pat;\r
9 \r
10 /** This class provides a method for parsing the "s/.../.../" constructs\r
11 of Regex.perlCode.\r
12 @see Regex#perlCode\r
13 */\r
14 class parsePerl {\r
15     final static char close(char c) {\r
16         // This switch statement does not behave\r
17         // properly when compiled with jdk1.1.5\r
18         // and the -O flag.\r
19         /*\r
20         switch(c) {\r
21         case '[':\r
22           return ']';\r
23         case '(':\r
24           return ')';\r
25         case '{':\r
26           return '}';\r
27         }\r
28         return c;*/\r
29         if(c == '<')\r
30             return '>';\r
31         if(c == '[')\r
32             return ']';\r
33         if(c == '(')\r
34             return ')';\r
35         if(c == '{')\r
36             return '}';\r
37         return c;\r
38     }\r
39 \r
40     final public static String codify(String s,boolean keepbs) {\r
41         return codify(s,0,s.length(),keepbs);\r
42     }\r
43     final public static String codify(String s,int i0,int iN,boolean keepbs) {\r
44         StringBuffer sb = new StringBuffer();\r
45         boolean ucmode = false, lcmode = false, litmode = false;\r
46         boolean uc1 = false, lc1 = false;\r
47         boolean modified = false;\r
48         for(int i=i0;i<iN;i++) {\r
49             char c = s.charAt(i);\r
50             boolean mf = true, app=true;\r
51             if(c=='\\') {\r
52                 app=false;\r
53                 i++;\r
54                 if(i<s.length()) {\r
55                     char c2 = s.charAt(i);\r
56                     switch(c2) {\r
57                     case 'Q':\r
58                         litmode = true;\r
59                         break;\r
60                     case 'U':\r
61                         ucmode = true;\r
62                         break;\r
63                     case 'L':\r
64                         lcmode = true;\r
65                         break;\r
66                     case 'u':\r
67                         uc1 = true;\r
68                         break;\r
69                     case 'l':\r
70                         lc1 = true;\r
71                         break;\r
72                     case 'E':\r
73                         uc1=lc1=ucmode=lcmode=litmode=false;\r
74                         break;\r
75                     default:\r
76                         if(keepbs)\r
77                             sb.append('\\');\r
78                         c=c2;\r
79                         if(keepbs) mf = false;\r
80                         app = true;\r
81                         break;\r
82                     }\r
83                     modified |= mf;\r
84                 }\r
85             }\r
86             if(app) {\r
87                 if(lc1) {\r
88                     c=lc(c);\r
89                     lc1=false;\r
90                 } else if(uc1) {\r
91                     c=uc(c);\r
92                     uc1=false;\r
93                 } else if(ucmode) {\r
94                     c=uc(c);\r
95                 } else if(lcmode) {\r
96                     c=lc(c);\r
97                 }\r
98                 if(litmode && needbs(c))\r
99                     sb.append('\\');\r
100                 sb.append(c);\r
101             }\r
102         }\r
103         return modified ? sb.toString() : s;\r
104     }\r
105     final static char uc(char c) {\r
106         return CaseMgr.toUpperCase(c);\r
107     }\r
108     final static char lc(char c) {\r
109         return CaseMgr.toLowerCase(c);\r
110     }\r
111     final static boolean needbs(char c) {\r
112         if(c >= 'a' && c <= 'z')\r
113             return false;\r
114         if(c >= 'A' && c <= 'Z')\r
115             return false;\r
116         if(c >= '0' && c <= '9')\r
117             return false;\r
118         if(c == '_')\r
119             return false;\r
120         return true;\r
121     }\r
122     final static Regex parse(String s) {\r
123         boolean igncase = false, optim = false, gFlag = false;\r
124         boolean sFlag = false, mFlag = false, xFlag = false;\r
125 \r
126         StringBuffer s1 = new StringBuffer();\r
127         StringBuffer s2 = new StringBuffer();\r
128         int i=0,count=0;\r
129         char mode,delim='/',cdelim='/';\r
130         if(s.length() >= 3 && s.charAt(0)=='s') {\r
131             mode = 's';\r
132             delim = s.charAt(1);\r
133             cdelim = close(delim);\r
134             i=2;\r
135         } else if(s.length() >= 2 && s.charAt(0)=='m') {\r
136             mode = 'm';\r
137             delim = s.charAt(1);\r
138             cdelim = close(delim);\r
139             i=2;\r
140         } else if(s.length() >= 1 && s.charAt(0)=='/') {\r
141             mode = 'm';\r
142             i=1;\r
143         } else {\r
144             try {\r
145                 RegSyntaxError.endItAll(\r
146                     "Regex.perlCode should be of the "+\r
147                     "form s/// or m// or //");\r
148             } catch(RegSyntax rs) {}\r
149             return null;\r
150         }\r
151         for(;i<s.length();i++) {\r
152             if(s.charAt(i)=='\\') {\r
153                 s1.append('\\');\r
154                 i++;\r
155             } else if(s.charAt(i)==cdelim && count==0) {\r
156                 i++;\r
157                 break;\r
158             } else if(s.charAt(i)==delim && cdelim != delim) {\r
159                 count++;\r
160             } else if(s.charAt(i)==cdelim && cdelim != delim) {\r
161                 count--;\r
162             }\r
163             s1.append(s.charAt(i));\r
164         }\r
165         if(mode=='s' && cdelim != delim) {\r
166             while(i<s.length() && Prop.isWhite(s.charAt(i)) )\r
167                 i++;\r
168             if(i>=s.length()) {\r
169                 try {\r
170                     RegSyntaxError.endItAll(""+mode+delim+" needs "+cdelim);\r
171                 } catch(RegSyntax rs) {}\r
172                 return null;\r
173             }\r
174             cdelim = close(delim = s.charAt(i));\r
175             i++;\r
176         }\r
177         count=0;\r
178         if(mode=='s') {\r
179             for(;i<s.length();i++) {\r
180                 if(s.charAt(i)=='\\') {\r
181                     s2.append('\\');\r
182                     i++;\r
183                 } else if(s.charAt(i)==cdelim && count==0) {\r
184                     i++;\r
185                     break;\r
186                 } else if(s.charAt(i)==delim && cdelim != delim) {\r
187                     count++;\r
188                 } else if(s.charAt(i)==cdelim && cdelim != delim) {\r
189                     count--;\r
190                 }\r
191                 s2.append(s.charAt(i));\r
192             }\r
193         }\r
194         for(;i<s.length();i++) {\r
195             char c = s.charAt(i);\r
196             switch(c) {\r
197             case 'x':\r
198                 xFlag = true;\r
199                 break;\r
200             case 'i':\r
201                 igncase = true;\r
202                 break;\r
203             case 'o':\r
204                 optim = true;\r
205                 break;\r
206             case 's':\r
207                 sFlag = true;\r
208                 break;\r
209             case 'm':\r
210                 mFlag = true;\r
211                 break;\r
212             case 'g':\r
213                 gFlag = true;\r
214                 break;\r
215             default:\r
216                 // syntax error!\r
217                 try {\r
218                     RegSyntaxError.endItAll("Illegal flag to pattern: "+c);\r
219                 } catch(RegSyntax rs) {}\r
220                 return null;\r
221             }\r
222         }\r
223         Regex r = new Regex();\r
224         try {\r
225             String pat=s1.toString(),reprul=s2.toString();\r
226             if(xFlag) {\r
227               pat = strip(pat);\r
228               reprul = strip(reprul);\r
229             }\r
230             r.compile(pat);\r
231             r.ignoreCase |= igncase;\r
232             r.gFlag |= gFlag;\r
233             r.sFlag |= sFlag;\r
234             r.mFlag |= mFlag;\r
235             if(optim) r.optimize();\r
236             if(delim=='\'')\r
237               r.setReplaceRule(new StringRule(reprul));\r
238             else\r
239               r.setReplaceRule(ReplaceRule.perlCode(reprul));\r
240         } catch(RegSyntax rs) {\r
241             r = null;\r
242         }\r
243         return r;\r
244     }\r
245     static String strip(String s) {\r
246       StringBuffer sb = new StringBuffer();\r
247       for(int i=0;i<s.length();i++) {\r
248         char c = s.charAt(i);\r
249         if(Prop.isWhite(c)) {\r
250           ;\r
251         } else if(c == '#') {\r
252           i++;\r
253           while(i<s.length()) {\r
254             if(s.charAt(i) == '\n')\r
255               break;\r
256             i++;\r
257           }\r
258         } else if(c == '\\') {\r
259           sb.append(c);\r
260           sb.append(s.charAt(++i));\r
261         } else\r
262           sb.append(c);\r
263       }\r
264       return sb.toString();\r
265     }\r
266 }\r