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
6 // -- Happy Computing!
\r
8 package com.stevesoft.pat;
\r
12 /** This class is a different form of Regex designed to work more
\r
13 like the file matching utility of a Unix shell. It is implemented
\r
14 by some simple string transformations:
\r
17 <tr> <td> FileRegex </td> <td> Regex </td>
\r
18 <tr> <td> * </td><td> .* </td>
\r
19 <tr> <td> . </td><td> \. </td>
\r
20 <tr> <td> { </td><td> (?: </td>
\r
21 <tr> <td> {?! </td><td> (?! </td>
\r
22 <tr> <td> {?= </td><td> (?= </td>
\r
23 <tr> <td> {?? </td><td> (?? </td>
\r
24 <tr> <td> } </td><td> ) </td>
\r
25 <tr> <td> ? </td><td> . </td>
\r
26 <tr> <td> {,} </td><td> (|) </td>
\r
29 Note that a FileRegex pattern always ends with the Regex
\r
30 pattern element "$". If you like to experiment, try making
\r
31 FileRegex's and then printing them out. The toString() method
\r
32 does a decompile of the pattern to a standard Regex. Here are
\r
33 some more complete examples:
\r
36 <tr> <td> FileRegex </td><td> Regex </td>
\r
37 <tr> <td>*.java </td><td> .*\.java$ </td>
\r
38 <tr> <td>*.{java,html} </td><td> .*\.(java|html)$ </td>
\r
39 <tr> <td> foo.[chC] </td><td> foo.[chC]$ </td>
\r
43 public class FileRegex extends Regex {
\r
44 /** Build an unitialized FileRegex. */
\r
45 public FileRegex() { dirflag=EITHER; }
\r
46 /** Build a FileRegex form String s. */
\r
47 public FileRegex(String s) {
\r
51 /** Compile a new pattern.
\r
52 Throws @exception com.stevesoft.pat.RegSyntax for
\r
53 nonsensical patterns like "[9-0]+" just as Regex does.
\r
54 @see com.stevesoft.pat#compile(java.lang.String)
\r
56 public void compile(String s) throws RegSyntax {
\r
57 String npat = toFileRegex(s);
\r
58 super.compile(npat);
\r
59 if(File.separatorChar == '\\') // MS-DOS
\r
62 /** This is the method required by FileNameFilter.
\r
63 To get a listing of files in the current directory
\r
64 ending in .java, do this:
\r
66 File dot = new File(".");
\r
67 FileRegex java_files = new FileRegex("*.java");
\r
68 String[] file_list = dot.list(java_files);
\r
71 public boolean accept(File dir,String s) {
\r
72 if(dirflag != EITHER) {
\r
73 File f = new File(s);
\r
74 if(f.isDirectory() && dirflag == NONDIR)
\r
76 if(!f.isDirectory() && dirflag == DIR)
\r
79 return matchAt(s,0);
\r
82 final static int EITHER=0,DIR=1,NONDIR=2;
\r
84 /** Provides an alternative to File.list -- this
\r
85 separates its argument according to File.pathSeparator.
\r
86 To each path, it splits off a directory -- all characters
\r
87 up to and including the first instance of File.separator --
\r
88 and a file pattern -- the part that comes after the directory.
\r
89 It then produces a list of all the pattern matches on all
\r
90 the paths. Thus "*.java:../*.java" would produce a list of
\r
91 all the java files in this directory and in the ".." directory
\r
92 on a Unix machine. "*.java;..\\*.java" would do the same thing
\r
93 on a Dos machine. */
\r
94 public static String[] list(String f) {
\r
95 return list(f,EITHER);
\r
97 static String[] list(String f,int df) {
\r
98 //return list_(f,new FileRegex());
\r
99 StringTokenizer st = new StringTokenizer(f,File.pathSeparator);
\r
100 Vector v = new Vector();
\r
101 while(st.hasMoreTokens()) {
\r
102 String path = st.nextToken();
\r
103 list1(path,v,df,true);
\r
105 String[] sa = new String[v.size()];
\r
109 final static Regex root=new Regex(File.separatorChar=='/' ?
\r
110 "/$" : "(?:.:|)\\\\$");
\r
111 static void list1(String path,Vector v,int df,boolean rec) {
\r
112 // if path looks like a/b/c/ or d:\ then add .
\r
113 if(root.matchAt(path,0)) {
\r
114 v.addElement(path+".");
\r
117 File f = new File(path);
\r
118 if(f.getParent() != null && rec) {
\r
119 Vector v2 = new Vector();
\r
120 list1(f.getParent(),v2,DIR,true);
\r
121 for(int i=0;i<v2.size();i++) {
\r
122 String path2 = ((String)v2.elementAt(i))+
\r
123 File.separator+f.getName();
\r
124 list1(path2,v,df,false);
\r
127 File base = new File(path);
\r
129 String dir_s = base.getParent();
\r
130 if(dir_s==null) dir_s=".";
\r
131 File dir = new File(dir_s);
\r
133 FileRegex fr = new FileRegex(base.getName());
\r
134 if(fr.isLiteral()) {
\r
135 v.addElement(dir_s+File.separator+base.getName());
\r
139 String[] sa = dir.list(fr);
\r
140 if(sa == null) return;
\r
141 for(int i=0;i<sa.length;i++) {
\r
142 v.addElement(dir_s+File.separator+sa[i]);
\r
147 /** This method takes a file regular expression, and translates it
\r
148 into the type of pattern used by a normal Regex. */
\r
149 public static String toFileRegex(String s) {
\r
150 StrPos sp = new StrPos(s,0);
\r
151 StringBuffer sb = new StringBuffer();
\r
152 if(sp.incMatch("{?e=")) {
\r
153 char e = sp.thisChar();
\r
155 if(sp.incMatch("}")) {
\r
156 sb.append("(?e="+e+")^");
\r
158 sb.append("^(?e=");
\r
164 if(File.separatorChar == '\\') {
\r
167 sp.dontMatch = false;
\r
169 if(sp.incMatch("?"))
\r
171 else if(sp.incMatch(".")) {
\r
174 } else if(sp.incMatch("{??")) {
\r
177 // allow negative lookahead to work
\r
178 } else if(sp.incMatch("{?!")) {
\r
181 // allow positive lookahead to work
\r
182 } else if(sp.incMatch("{?=")) {
\r
185 } else if(sp.incMatch("{")) {
\r
188 } else if(sp.incMatch("}")) {
\r
191 } else if(ParenLvl != 0 && sp.incMatch(","))
\r
193 else if(sp.incMatch("*"))
\r
196 sb.append(sp.thisChar());
\r
201 return sb.toString();
\r
203 public boolean isLiteral() {
\r
204 Pattern x = thePattern;
\r
205 while(x != null && !(x instanceof End)) {
\r
206 if(x instanceof oneChar)
\r
208 else if(x instanceof Skipped)
\r