needed for applet search
[jalview.git] / src / com / stevesoft / pat / FileRegex.java
diff --git a/src/com/stevesoft/pat/FileRegex.java b/src/com/stevesoft/pat/FileRegex.java
new file mode 100755 (executable)
index 0000000..f5ac448
--- /dev/null
@@ -0,0 +1,215 @@
+//\r
+// This software is now distributed according to\r
+// the Lesser Gnu Public License.  Please see\r
+// http://www.gnu.org/copyleft/lesser.txt for\r
+// the details.\r
+//    -- Happy Computing!\r
+//\r
+package com.stevesoft.pat;\r
+import java.io.*;\r
+import java.util.*;\r
+\r
+/** This class is a different form of Regex designed to work more\r
+ like the file matching utility of a Unix shell.  It is implemented\r
+ by some simple string transformations:\r
+ <center>\r
+ <table border=1>\r
+ <tr> <td> FileRegex </td> <td> Regex </td>\r
+ <tr> <td> * </td><td> .* </td>\r
+ <tr> <td> . </td><td> \. </td>\r
+ <tr> <td> { </td><td> (?: </td>\r
+ <tr> <td> {?! </td><td> (?! </td>\r
+ <tr> <td> {?= </td><td> (?= </td>\r
+ <tr> <td> {?? </td><td> (?? </td>\r
+ <tr> <td> } </td><td> ) </td>\r
+ <tr> <td> ? </td><td> . </td>\r
+ <tr> <td> {,} </td><td> (|) </td>\r
+ </table>\r
+ </center>\r
+ Note that a FileRegex pattern always ends with the Regex\r
+ pattern element "$".  If you like to experiment, try making\r
+ FileRegex's and then printing them out.  The toString() method\r
+ does a decompile of the pattern to a standard Regex.  Here are\r
+ some more complete examples:\r
+ <center>\r
+ <table border=3>\r
+ <tr> <td> FileRegex </td><td> Regex </td>\r
+ <tr> <td>*.java </td><td> .*\.java$ </td>\r
+ <tr> <td>*.{java,html} </td><td> .*\.(java|html)$ </td>\r
+ <tr> <td> foo.[chC] </td><td> foo.[chC]$ </td>\r
+ </table>\r
+ </center>\r
+ */\r
+public class FileRegex extends Regex {\r
+    /** Build an unitialized FileRegex. */\r
+    public FileRegex() { dirflag=EITHER; }\r
+    /** Build a FileRegex form String s. */\r
+    public FileRegex(String s) {\r
+        super(s);\r
+        dirflag = EITHER;\r
+    }\r
+    /** Compile a new pattern.\r
+        Throws @exception com.stevesoft.pat.RegSyntax for\r
+        nonsensical patterns like "[9-0]+" just as Regex does.\r
+        @see com.stevesoft.pat#compile(java.lang.String)\r
+        */\r
+    public void compile(String s) throws RegSyntax {\r
+       String npat = toFileRegex(s);\r
+        super.compile(npat);\r
+        if(File.separatorChar == '\\') // MS-DOS\r
+            ignoreCase = true;\r
+    }\r
+    /** This is the method required by FileNameFilter.\r
+       To get a listing of files in the current directory\r
+         ending in .java, do this:\r
+        <pre>\r
+        File dot = new File(".");\r
+        FileRegex java_files = new FileRegex("*.java");\r
+        String[] file_list = dot.list(java_files);\r
+        </pre>\r
+        */\r
+    public boolean accept(File dir,String s) {\r
+        if(dirflag != EITHER) {\r
+            File f = new File(s);\r
+            if(f.isDirectory() && dirflag == NONDIR)\r
+                return false;\r
+            if(!f.isDirectory() && dirflag == DIR)\r
+                return false;\r
+        }\r
+        return matchAt(s,0);\r
+    }\r
+    int dirflag = 0;\r
+    final static int EITHER=0,DIR=1,NONDIR=2;\r
+\r
+    /** Provides an alternative to File.list -- this\r
+        separates its argument according to File.pathSeparator.\r
+        To each path, it splits off a directory -- all characters\r
+        up to and including the first instance of File.separator --\r
+        and a file pattern -- the part that comes after the directory.\r
+        It then produces a list of all the pattern matches on all\r
+        the paths.  Thus "*.java:../*.java" would produce a list of\r
+        all the java files in this directory and in the ".." directory\r
+        on a Unix machine.  "*.java;..\\*.java" would do the same thing\r
+        on a Dos machine. */\r
+    public static String[] list(String f) {\r
+        return list(f,EITHER);\r
+    }\r
+    static String[] list(String f,int df) {\r
+        //return list_(f,new FileRegex());\r
+        StringTokenizer st = new StringTokenizer(f,File.pathSeparator);\r
+        Vector v = new Vector();\r
+        while(st.hasMoreTokens()) {\r
+            String path = st.nextToken();\r
+            list1(path,v,df,true);\r
+        }\r
+        String[] sa = new String[v.size()];\r
+        v.copyInto(sa);\r
+        return sa;\r
+    }\r
+    final static Regex root=new Regex(File.separatorChar=='/' ?\r
+        "/$" : "(?:.:|)\\\\$");\r
+    static void list1(String path,Vector v,int df,boolean rec) {\r
+       // if path looks like a/b/c/ or d:\ then add .\r
+        if(root.matchAt(path,0)) {\r
+            v.addElement(path+".");\r
+            return;\r
+        }\r
+        File f = new File(path);\r
+        if(f.getParent() != null && rec) {\r
+            Vector v2 = new Vector();\r
+            list1(f.getParent(),v2,DIR,true);\r
+            for(int i=0;i<v2.size();i++) {\r
+                String path2 = ((String)v2.elementAt(i))+\r
+                    File.separator+f.getName();\r
+                list1(path2,v,df,false);\r
+            }\r
+        } else {\r
+            File base = new File(path);\r
+\r
+            String dir_s = base.getParent();\r
+            if(dir_s==null) dir_s=".";\r
+            File dir = new File(dir_s);\r
+\r
+            FileRegex fr = new FileRegex(base.getName());\r
+            if(fr.isLiteral()) {\r
+                v.addElement(dir_s+File.separator+base.getName());\r
+                return;\r
+            }\r
+            fr.dirflag = df;\r
+            String[] sa = dir.list(fr);\r
+            if(sa == null) return;\r
+            for(int i=0;i<sa.length;i++) {\r
+                v.addElement(dir_s+File.separator+sa[i]);\r
+            }\r
+        }\r
+    }\r
+\r
+    /** This method takes a file regular expression, and translates it\r
+            into the type of pattern used by a normal Regex. */\r
+    public static String toFileRegex(String s) {\r
+        StrPos sp = new StrPos(s,0);\r
+        StringBuffer sb = new StringBuffer();\r
+        if(sp.incMatch("{?e=")) {\r
+            char e = sp.thisChar();\r
+            sp.inc();\r
+            if(sp.incMatch("}")) {\r
+                sb.append("(?e="+e+")^");\r
+            } else {\r
+                sb.append("^(?e=");\r
+            }\r
+            sp.esc = e;\r
+        }\r
+        int ParenLvl = 0;\r
+        while(!sp.eos()) {\r
+           if(File.separatorChar == '\\') {\r
+             if(sp.escaped())\r
+               sb.append("\\\\");\r
+             sp.dontMatch = false;\r
+           }\r
+            if(sp.incMatch("?"))\r
+                sb.append(".");\r
+            else if(sp.incMatch(".")) {\r
+                sb.append(sp.esc);\r
+                sb.append('.');\r
+            } else if(sp.incMatch("{??")) {\r
+                sb.append("(??");\r
+                ParenLvl++;\r
+                // allow negative lookahead to work\r
+            } else if(sp.incMatch("{?!")) {\r
+                sb.append("(?!");\r
+                ParenLvl++;\r
+                // allow positive lookahead to work\r
+            } else if(sp.incMatch("{?=")) {\r
+                sb.append("(?=");\r
+                ParenLvl++;\r
+            } else if(sp.incMatch("{")) {\r
+                sb.append("(?:");\r
+                ParenLvl++;\r
+            } else if(sp.incMatch("}")) {\r
+                sb.append(')');\r
+                ParenLvl--;\r
+            } else if(ParenLvl != 0 && sp.incMatch(","))\r
+                sb.append('|');\r
+            else if(sp.incMatch("*"))\r
+                sb.append(".*");\r
+            else {\r
+                sb.append(sp.thisChar());\r
+                sp.inc();\r
+            }\r
+        }\r
+        sb.append("$");\r
+        return sb.toString();\r
+    }\r
+    public boolean isLiteral() {\r
+        Pattern x = thePattern;\r
+        while(x != null && !(x instanceof End)) {\r
+            if(x instanceof oneChar)\r
+                ;\r
+            else if(x instanceof Skipped)\r
+                ;\r
+            else return false;\r
+            x = x.next;\r
+        }\r
+        return true;\r
+    }\r
+}\r