needed for applet search
[jalview.git] / src / com / stevesoft / pat / Pattern.java
diff --git a/src/com/stevesoft/pat/Pattern.java b/src/com/stevesoft/pat/Pattern.java
new file mode 100755 (executable)
index 0000000..404991c
--- /dev/null
@@ -0,0 +1,193 @@
+//\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.util.*;\r
+/**\r
+        Shareware: package pat\r
+   <a href="copyright.html">Copyright 2001, Steven R. Brandt</a>\r
+*/ /**\r
+Class Pattern is the base class on which all the other pattern\r
+elements are built. */\r
+\r
+public abstract class Pattern {\r
+    /** The ESC character, the user can provide his own value\r
+            for the escape character through regex.esc */\r
+    public final static char ESC = '\\';\r
+    final static String PROTECT_THESE = "[]{}(),$,-\"^.";\r
+\r
+    /** The interal match function, it must be provided by any\r
+        class which wishes to extend Pattern. */\r
+    public abstract int matchInternal(int i,Pthings p);\r
+    public abstract String toString();\r
+\r
+    // Class Pattern is a singly linked list\r
+    // chained together by member next.  The member\r
+    // parent is used so that sub patterns can access\r
+    // the chain they are branching from.\r
+    Pattern next=null,parent=null;\r
+\r
+    /** This gets the next element of a Pattern that\r
+            we wish to match.  If we are at the end of a\r
+            subchain of patterns, it will return us to the\r
+            parent chain. */\r
+    public Pattern getNext() {\r
+        return next != null ? next :\r
+        (parent == null ? null : parent.getNext());\r
+    }\r
+    /** Call this method if you have a pattern element that\r
+            takes a sub pattern (such as Or), and\r
+            after you have added a sub pattern to the current\r
+            pattern element. */\r
+    public void setParent(Pattern p) {\r
+        if(next != null) next.setParent(p);\r
+        else parent = p;\r
+    }\r
+    /** This determines if the remainder of a Pattern\r
+            matches.  Type "return nextMatch" from within\r
+            matchInternal if the current\r
+            Pattern matches.  Otherwise, return a -1.*/\r
+    public int nextMatch(int i,Pthings pt) {\r
+        Pattern p = getNext();\r
+        /*if(p == null) return i;\r
+                return p.matchInternal(i,pt);*/\r
+        return p==null ? i : p.matchInternal(i,pt);\r
+    }\r
+    /** This is a toString() for the remainder\r
+            of the Pattern elements after this one.\r
+            use this when overriding toString(). Called from\r
+            within toString(). */\r
+    public String nextString() {\r
+        if(next == null) return "";\r
+        return next.toString();\r
+    }\r
+\r
+    /** a method to detect whether char c is in String s */\r
+    final static boolean inString(char c,String s) {\r
+        int i;\r
+        for(i=0;i<s.length();i++)\r
+            if(s.charAt(i)==c)\r
+                return true;\r
+        return false;\r
+    }\r
+\r
+    /** A method to create a string that protects the characters\r
+            listed in PROTECT_THESE by prepending the esc character.\r
+            The esc character itself is automatically protected. */\r
+    final static\r
+        String protect(String s,String PROTECT_THESE,char esc) {\r
+        int i;\r
+        StringBuffer sb = new StringBuffer();\r
+        String p = PROTECT_THESE+esc;\r
+        for(i=0;i<s.length();i++) {\r
+            char c = s.charAt(i);\r
+            if(inString(c,p))\r
+                sb.append(esc);\r
+            sb.append(c);\r
+        }\r
+        return sb.toString();\r
+    }\r
+\r
+    /** This can be used to perform a match test from\r
+            within class Pattern. */\r
+    public int match(StringLike s,Pthings pt) {\r
+        return matchAt(s,0,pt);\r
+    }\r
+    /** This can be used to perform a match test from\r
+            within class Pattern. */\r
+    public int matchAt(StringLike s,int i,Pthings pt) {\r
+        pt.src = s;\r
+        int r = matchInternal(i,pt);\r
+        if(r < 0) return -1;\r
+        mfrom = r<i ? r+1 : i;\r
+        return r<i ? i-r-1 : r-i;\r
+    }\r
+    int mfrom=0;\r
+\r
+    // Detect masked characters\r
+    final boolean Masked(int i,Pthings pt) {\r
+        return pt.cbits == null ? false : pt.cbits.get(i);\r
+    }\r
+\r
+    /** add a Pattern to the singly-linked Pattern chain. */\r
+    public Pattern add(Pattern p) {\r
+        if(next == null) {\r
+            if(p==null) return this;\r
+            next = p;\r
+            p.parent = parent;\r
+            parent = null;\r
+        } else next.add(p);\r
+        return this;\r
+    }\r
+    /** The minimum number of characters which\r
+        this pattern element can match. */\r
+    public patInt minChars() { return new patInt(0); }\r
+    /** The maximum number of characters which\r
+        this pattern element can match. */\r
+    public patInt maxChars() { return new patInf(); }\r
+    /** return minimum number of characters in pattern */\r
+    public final patInt countMinChars() {\r
+        Pattern p = this;\r
+        patInt sum = new patInt(0);\r
+        while(p != null) {\r
+            sum.pluseq(p.minChars());\r
+            p = p.next;\r
+        }\r
+        return sum;\r
+    }\r
+    /** return maximum number of characters in pattern */\r
+    public final patInt countMaxChars() {\r
+        Pattern p = this;\r
+        patInt sum = new patInt(0);\r
+        while(p != null) {\r
+            sum.pluseq(p.maxChars());\r
+            p = p.next;\r
+        }\r
+        return sum;\r
+    }\r
+\r
+    // This method is only needed by Multi_stage2 so far...\r
+    // the reason is that it may try something else after a\r
+    // match succeeds.  OrMark will only record the last thing\r
+    // tried in marks, so we need to backup the result of the\r
+    // last successful match and restore it if the next one\r
+    // does not succeed.\r
+    final int testMatch(Pattern p,int pos,Pthings pt) {\r
+        int[] tab = null;\r
+        if(pt.marks != null) try {\r
+                tab = new int[pt.marks.length];\r
+                for(int i=0;i<tab.length;i++)\r
+                    tab[i] = pt.marks[i];\r
+            } catch(Throwable t) {}\r
+        int ret = p.matchInternal(pos,pt);\r
+        if(ret < 0) pt.marks = tab;\r
+        return ret;\r
+    }\r
+\r
+    /** Clones this pattern elements without cloning others in the\r
+        linked list. */\r
+    Pattern clone1(Hashtable h) {\r
+        throw new Error("No such method as clone1 for "+getClass().getName());\r
+    }\r
+    Pattern clone(Hashtable h) {\r
+        Pattern p = (Pattern)h.get(this);\r
+        if(p != null) {\r
+            return p;\r
+        }\r
+        p=clone1(h);\r
+        if(p==null)throw new Error("Null from clone1!");\r
+        h.put(this,p);\r
+        h.put(p,p);\r
+        if(next != null) p.next = next.clone(h);\r
+        if(parent != null) p.parent = parent.clone(h);\r
+        return p;\r
+    }\r
+    public boolean equals(Object o) {\r
+        return o == this;\r
+    }\r
+};\r
+\r