Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
FileRegex | 70 | 100 | 43 |
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.File; | |
11 | import java.util.StringTokenizer; | |
12 | import java.util.Vector; | |
13 | ||
14 | /** | |
15 | * This class is a different form of Regex designed to work more like the file | |
16 | * matching utility of a Unix shell. It is implemented by some simple string | |
17 | * transformations: <center> | |
18 | * <table border=1> | |
19 | * <tr> | |
20 | * <td>FileRegex</td> | |
21 | * <td>Regex</td> | |
22 | * <tr> | |
23 | * <td>*</td> | |
24 | * <td>.*</td> | |
25 | * <tr> | |
26 | * <td>.</td> | |
27 | * <td>\.</td> | |
28 | * <tr> | |
29 | * <td>{</td> | |
30 | * <td>(?:</td> | |
31 | * <tr> | |
32 | * <td>{?!</td> | |
33 | * <td>(?!</td> | |
34 | * <tr> | |
35 | * <td>{?=</td> | |
36 | * <td>(?=</td> | |
37 | * <tr> | |
38 | * <td>{??</td> | |
39 | * <td>(??</td> | |
40 | * <tr> | |
41 | * <td></td> | |
42 | * <td>)</td> | |
43 | * <tr> | |
44 | * <td>?</td> | |
45 | * <td>.</td> | |
46 | * <tr> | |
47 | * <td>{,}</td> | |
48 | * <td>(|)</td> | |
49 | * </table> | |
50 | * </center> Note that a FileRegex pattern always ends with the Regex pattern | |
51 | * element "$". If you like to experiment, try making FileRegex's and then | |
52 | * printing them out. The toString() method does a decompile of the pattern to a | |
53 | * standard Regex. Here are some more complete examples: <center> <table * | |
54 | * border=3> | |
55 | * <tr> | |
56 | * <td>FileRegex</td> | |
57 | * <td>Regex</td> | |
58 | * <tr> | |
59 | * <td>*.java</td> | |
60 | * <td>.*\.java$</td> | |
61 | * <tr> | |
62 | * <td>*.{java,html}</td> | |
63 | * <td>.*\.(java|html)$</td> | |
64 | * <tr> | |
65 | * <td>foo.[chC]</td> | |
66 | * <td>foo.[chC]$</td> | |
67 | * </table> | |
68 | * </center> | |
69 | */ | |
70 | public class FileRegex extends Regex | |
71 | { | |
72 | /** Build an unitialized FileRegex. */ | |
73 | 0 | public FileRegex() |
74 | { | |
75 | 0 | dirflag = EITHER; |
76 | } | |
77 | ||
78 | /** Build a FileRegex form String s. */ | |
79 | 0 | public FileRegex(String s) |
80 | { | |
81 | 0 | super(s); |
82 | 0 | dirflag = EITHER; |
83 | } | |
84 | ||
85 | /** | |
86 | * Compile a new pattern. Throws | |
87 | * | |
88 | * @exception com.stevesoft.pat.RegSyntax | |
89 | * for nonsensical patterns like "[9-0]+" just as Regex does. | |
90 | * @see com.stevesoft.pat#compile(java.lang.String) | |
91 | */ | |
92 | 0 | public void compile(String s) throws RegSyntax |
93 | { | |
94 | 0 | String npat = toFileRegex(s); |
95 | 0 | super.compile(npat); |
96 | 0 | if (File.separatorChar == '\\') // MS-DOS |
97 | { | |
98 | 0 | ignoreCase = true; |
99 | } | |
100 | } | |
101 | ||
102 | /** | |
103 | * This is the method required by FileNameFilter. To get a listing of files in | |
104 | * the current directory ending in .java, do this: | |
105 | * | |
106 | * <pre> | |
107 | * File dot = new File("."); | |
108 | * | |
109 | * FileRegex java_files = new FileRegex("*.java"); | |
110 | * | |
111 | * String[] file_list = dot.list(java_files); | |
112 | * </pre> | |
113 | */ | |
114 | 0 | public boolean accept(File dir, String s) |
115 | { | |
116 | 0 | if (dirflag != EITHER) |
117 | { | |
118 | 0 | File f = new File(s); |
119 | 0 | if (f.isDirectory() && dirflag == NONDIR) |
120 | { | |
121 | 0 | return false; |
122 | } | |
123 | 0 | if (!f.isDirectory() && dirflag == DIR) |
124 | { | |
125 | 0 | return false; |
126 | } | |
127 | } | |
128 | 0 | return matchAt(s, 0); |
129 | } | |
130 | ||
131 | int dirflag = 0; | |
132 | ||
133 | final static int EITHER = 0, DIR = 1, NONDIR = 2; | |
134 | ||
135 | /** | |
136 | * Provides an alternative to File.list -- this separates its argument | |
137 | * according to File.pathSeparator. To each path, it splits off a directory -- | |
138 | * all characters up to and including the first instance of File.separator -- | |
139 | * and a file pattern -- the part that comes after the directory. It then | |
140 | * produces a list of all the pattern matches on all the paths. Thus | |
141 | * "*.java:../*.java" would produce a list of all the java files in this | |
142 | * directory and in the ".." directory on a Unix machine. "*.java;..\\*.java" | |
143 | * would do the same thing on a Dos machine. | |
144 | */ | |
145 | 0 | public static String[] list(String f) |
146 | { | |
147 | 0 | return list(f, EITHER); |
148 | } | |
149 | ||
150 | 0 | static String[] list(String f, int df) |
151 | { | |
152 | // return list_(f,new FileRegex()); | |
153 | 0 | StringTokenizer st = new StringTokenizer(f, File.pathSeparator); |
154 | 0 | Vector v = new Vector(); |
155 | 0 | while (st.hasMoreTokens()) |
156 | { | |
157 | 0 | String path = st.nextToken(); |
158 | 0 | list1(path, v, df, true); |
159 | } | |
160 | 0 | String[] sa = new String[v.size()]; |
161 | 0 | v.copyInto(sa); |
162 | 0 | return sa; |
163 | } | |
164 | ||
165 | final static Regex root = new Regex( | |
166 | File.separatorChar == '/' ? "/$" : "(?:.:|)\\\\$"); | |
167 | ||
168 | 0 | static void list1(String path, Vector v, int df, boolean rec) |
169 | { | |
170 | // if path looks like a/b/c/ or d:\ then add . | |
171 | 0 | if (root.matchAt(path, 0)) |
172 | { | |
173 | 0 | v.addElement(path + "."); |
174 | 0 | return; |
175 | } | |
176 | 0 | File f = new File(path); |
177 | 0 | if (f.getParent() != null && rec) |
178 | { | |
179 | 0 | Vector v2 = new Vector(); |
180 | 0 | list1(f.getParent(), v2, DIR, true); |
181 | 0 | for (int i = 0; i < v2.size(); i++) |
182 | { | |
183 | 0 | String path2 = ((String) v2.elementAt(i)) + File.separator |
184 | + f.getName(); | |
185 | 0 | list1(path2, v, df, false); |
186 | } | |
187 | } | |
188 | else | |
189 | { | |
190 | 0 | File base = new File(path); |
191 | ||
192 | 0 | String dir_s = base.getParent(); |
193 | 0 | if (dir_s == null) |
194 | { | |
195 | 0 | dir_s = "."; |
196 | } | |
197 | 0 | File dir = new File(dir_s); |
198 | ||
199 | 0 | FileRegex fr = new FileRegex(base.getName()); |
200 | 0 | if (fr.isLiteral()) |
201 | { | |
202 | 0 | v.addElement(dir_s + File.separator + base.getName()); |
203 | 0 | return; |
204 | } | |
205 | 0 | fr.dirflag = df; |
206 | 0 | String[] sa = dir.list(fr); |
207 | 0 | if (sa == null) |
208 | { | |
209 | 0 | return; |
210 | } | |
211 | 0 | for (int i = 0; i < sa.length; i++) |
212 | { | |
213 | 0 | v.addElement(dir_s + File.separator + sa[i]); |
214 | } | |
215 | } | |
216 | } | |
217 | ||
218 | /** | |
219 | * This method takes a file regular expression, and translates it into the | |
220 | * type of pattern used by a normal Regex. | |
221 | */ | |
222 | 0 | public static String toFileRegex(String s) |
223 | { | |
224 | 0 | StrPos sp = new StrPos(s, 0); |
225 | 0 | StringBuffer sb = new StringBuffer(); |
226 | 0 | if (sp.incMatch("{?e=")) |
227 | { | |
228 | 0 | char e = sp.thisChar(); |
229 | 0 | sp.inc(); |
230 | 0 | if (sp.incMatch("}")) |
231 | { | |
232 | 0 | sb.append("(?e=" + e + ")^"); |
233 | } | |
234 | else | |
235 | { | |
236 | 0 | sb.append("^(?e="); |
237 | } | |
238 | 0 | sp.esc = e; |
239 | } | |
240 | 0 | int ParenLvl = 0; |
241 | 0 | while (!sp.eos()) |
242 | { | |
243 | 0 | if (File.separatorChar == '\\') |
244 | { | |
245 | 0 | if (sp.escaped()) |
246 | { | |
247 | 0 | sb.append("\\\\"); |
248 | } | |
249 | 0 | sp.dontMatch = false; |
250 | } | |
251 | 0 | if (sp.incMatch("?")) |
252 | { | |
253 | 0 | sb.append("."); |
254 | } | |
255 | 0 | else if (sp.incMatch(".")) |
256 | { | |
257 | 0 | sb.append(sp.esc); |
258 | 0 | sb.append('.'); |
259 | } | |
260 | 0 | else if (sp.incMatch("{??")) |
261 | { | |
262 | 0 | sb.append("(??"); |
263 | 0 | ParenLvl++; |
264 | // allow negative lookahead to work | |
265 | } | |
266 | 0 | else if (sp.incMatch("{?!")) |
267 | { | |
268 | 0 | sb.append("(?!"); |
269 | 0 | ParenLvl++; |
270 | // allow positive lookahead to work | |
271 | } | |
272 | 0 | else if (sp.incMatch("{?=")) |
273 | { | |
274 | 0 | sb.append("(?="); |
275 | 0 | ParenLvl++; |
276 | } | |
277 | 0 | else if (sp.incMatch("{")) |
278 | { | |
279 | 0 | sb.append("(?:"); |
280 | 0 | ParenLvl++; |
281 | } | |
282 | 0 | else if (sp.incMatch("}")) |
283 | { | |
284 | 0 | sb.append(')'); |
285 | 0 | ParenLvl--; |
286 | } | |
287 | 0 | else if (ParenLvl != 0 && sp.incMatch(",")) |
288 | { | |
289 | 0 | sb.append('|'); |
290 | } | |
291 | 0 | else if (sp.incMatch("*")) |
292 | { | |
293 | 0 | sb.append(".*"); |
294 | } | |
295 | else | |
296 | { | |
297 | 0 | sb.append(sp.thisChar()); |
298 | 0 | sp.inc(); |
299 | } | |
300 | } | |
301 | 0 | sb.append("$"); |
302 | 0 | return sb.toString(); |
303 | } | |
304 | ||
305 | 0 | public boolean isLiteral() |
306 | { | |
307 | 0 | Pattern x = thePattern; |
308 | 0 | while (x != null && !(x instanceof End)) |
309 | { | |
310 | 0 | if (x instanceof oneChar) |
311 | { | |
312 | 0 | ; |
313 | } | |
314 | 0 | else if (x instanceof Skipped) |
315 | { | |
316 | 0 | ; |
317 | } | |
318 | else | |
319 | { | |
320 | 0 | return false; |
321 | } | |
322 | 0 | x = x.next; |
323 | } | |
324 | 0 | return true; |
325 | } | |
326 | } |