spelling err
[jalview.git] / src / com / stevesoft / pat / FileRegex.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 import java.io.*;\r
10 import java.util.*;\r
11 \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
15  <center>\r
16  <table border=1>\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
27  </table>\r
28  </center>\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
34  <center>\r
35  <table border=3>\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
40  </table>\r
41  </center>\r
42  */\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
48         super(s);\r
49         dirflag = EITHER;\r
50     }\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
55         */\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
60             ignoreCase = true;\r
61     }\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
65         <pre>\r
66         File dot = new File(".");\r
67         FileRegex java_files = new FileRegex("*.java");\r
68         String[] file_list = dot.list(java_files);\r
69         </pre>\r
70         */\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
75                 return false;\r
76             if(!f.isDirectory() && dirflag == DIR)\r
77                 return false;\r
78         }\r
79         return matchAt(s,0);\r
80     }\r
81     int dirflag = 0;\r
82     final static int EITHER=0,DIR=1,NONDIR=2;\r
83 \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
96     }\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
104         }\r
105         String[] sa = new String[v.size()];\r
106         v.copyInto(sa);\r
107         return sa;\r
108     }\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
115             return;\r
116         }\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
125             }\r
126         } else {\r
127             File base = new File(path);\r
128 \r
129             String dir_s = base.getParent();\r
130             if(dir_s==null) dir_s=".";\r
131             File dir = new File(dir_s);\r
132 \r
133             FileRegex fr = new FileRegex(base.getName());\r
134             if(fr.isLiteral()) {\r
135                 v.addElement(dir_s+File.separator+base.getName());\r
136                 return;\r
137             }\r
138             fr.dirflag = df;\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
143             }\r
144         }\r
145     }\r
146 \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
154             sp.inc();\r
155             if(sp.incMatch("}")) {\r
156                 sb.append("(?e="+e+")^");\r
157             } else {\r
158                 sb.append("^(?e=");\r
159             }\r
160             sp.esc = e;\r
161         }\r
162         int ParenLvl = 0;\r
163         while(!sp.eos()) {\r
164             if(File.separatorChar == '\\') {\r
165               if(sp.escaped())\r
166                 sb.append("\\\\");\r
167               sp.dontMatch = false;\r
168             }\r
169             if(sp.incMatch("?"))\r
170                 sb.append(".");\r
171             else if(sp.incMatch(".")) {\r
172                 sb.append(sp.esc);\r
173                 sb.append('.');\r
174             } else if(sp.incMatch("{??")) {\r
175                 sb.append("(??");\r
176                 ParenLvl++;\r
177                 // allow negative lookahead to work\r
178             } else if(sp.incMatch("{?!")) {\r
179                 sb.append("(?!");\r
180                 ParenLvl++;\r
181                 // allow positive lookahead to work\r
182             } else if(sp.incMatch("{?=")) {\r
183                 sb.append("(?=");\r
184                 ParenLvl++;\r
185             } else if(sp.incMatch("{")) {\r
186                 sb.append("(?:");\r
187                 ParenLvl++;\r
188             } else if(sp.incMatch("}")) {\r
189                 sb.append(')');\r
190                 ParenLvl--;\r
191             } else if(ParenLvl != 0 && sp.incMatch(","))\r
192                 sb.append('|');\r
193             else if(sp.incMatch("*"))\r
194                 sb.append(".*");\r
195             else {\r
196                 sb.append(sp.thisChar());\r
197                 sp.inc();\r
198             }\r
199         }\r
200         sb.append("$");\r
201         return sb.toString();\r
202     }\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
207                 ;\r
208             else if(x instanceof Skipped)\r
209                 ;\r
210             else return false;\r
211             x = x.next;\r
212         }\r
213         return true;\r
214     }\r
215 }\r