Graphical bits moved into files to save jar size
[jalview.git] / src / com / stevesoft / pat / Pattern.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.util.*;\r
10 /**\r
11         Shareware: package pat\r
12    <a href="copyright.html">Copyright 2001, Steven R. Brandt</a>\r
13 */ /**\r
14 Class Pattern is the base class on which all the other pattern\r
15 elements are built. */\r
16 \r
17 public abstract class Pattern {\r
18     /** The ESC character, the user can provide his own value\r
19             for the escape character through regex.esc */\r
20     public final static char ESC = '\\';\r
21     final static String PROTECT_THESE = "[]{}(),$,-\"^.";\r
22 \r
23     /** The interal match function, it must be provided by any\r
24         class which wishes to extend Pattern. */\r
25     public abstract int matchInternal(int i,Pthings p);\r
26     public abstract String toString();\r
27 \r
28     // Class Pattern is a singly linked list\r
29     // chained together by member next.  The member\r
30     // parent is used so that sub patterns can access\r
31     // the chain they are branching from.\r
32     Pattern next=null,parent=null;\r
33 \r
34     /** This gets the next element of a Pattern that\r
35             we wish to match.  If we are at the end of a\r
36             subchain of patterns, it will return us to the\r
37             parent chain. */\r
38     public Pattern getNext() {\r
39         return next != null ? next :\r
40         (parent == null ? null : parent.getNext());\r
41     }\r
42     /** Call this method if you have a pattern element that\r
43             takes a sub pattern (such as Or), and\r
44             after you have added a sub pattern to the current\r
45             pattern element. */\r
46     public void setParent(Pattern p) {\r
47         if(next != null) next.setParent(p);\r
48         else parent = p;\r
49     }\r
50     /** This determines if the remainder of a Pattern\r
51             matches.  Type "return nextMatch" from within\r
52             matchInternal if the current\r
53             Pattern matches.  Otherwise, return a -1.*/\r
54     public int nextMatch(int i,Pthings pt) {\r
55         Pattern p = getNext();\r
56         /*if(p == null) return i;\r
57                 return p.matchInternal(i,pt);*/\r
58         return p==null ? i : p.matchInternal(i,pt);\r
59     }\r
60     /** This is a toString() for the remainder\r
61             of the Pattern elements after this one.\r
62             use this when overriding toString(). Called from\r
63             within toString(). */\r
64     public String nextString() {\r
65         if(next == null) return "";\r
66         return next.toString();\r
67     }\r
68 \r
69     /** a method to detect whether char c is in String s */\r
70     final static boolean inString(char c,String s) {\r
71         int i;\r
72         for(i=0;i<s.length();i++)\r
73             if(s.charAt(i)==c)\r
74                 return true;\r
75         return false;\r
76     }\r
77 \r
78     /** A method to create a string that protects the characters\r
79             listed in PROTECT_THESE by prepending the esc character.\r
80             The esc character itself is automatically protected. */\r
81     final static\r
82         String protect(String s,String PROTECT_THESE,char esc) {\r
83         int i;\r
84         StringBuffer sb = new StringBuffer();\r
85         String p = PROTECT_THESE+esc;\r
86         for(i=0;i<s.length();i++) {\r
87             char c = s.charAt(i);\r
88             if(inString(c,p))\r
89                 sb.append(esc);\r
90             sb.append(c);\r
91         }\r
92         return sb.toString();\r
93     }\r
94 \r
95     /** This can be used to perform a match test from\r
96             within class Pattern. */\r
97     public int match(StringLike s,Pthings pt) {\r
98         return matchAt(s,0,pt);\r
99     }\r
100     /** This can be used to perform a match test from\r
101             within class Pattern. */\r
102     public int matchAt(StringLike s,int i,Pthings pt) {\r
103         pt.src = s;\r
104         int r = matchInternal(i,pt);\r
105         if(r < 0) return -1;\r
106         mfrom = r<i ? r+1 : i;\r
107         return r<i ? i-r-1 : r-i;\r
108     }\r
109     int mfrom=0;\r
110 \r
111     // Detect masked characters\r
112     final boolean Masked(int i,Pthings pt) {\r
113         return pt.cbits == null ? false : pt.cbits.get(i);\r
114     }\r
115 \r
116     /** add a Pattern to the singly-linked Pattern chain. */\r
117     public Pattern add(Pattern p) {\r
118         if(next == null) {\r
119             if(p==null) return this;\r
120             next = p;\r
121             p.parent = parent;\r
122             parent = null;\r
123         } else next.add(p);\r
124         return this;\r
125     }\r
126     /** The minimum number of characters which\r
127         this pattern element can match. */\r
128     public patInt minChars() { return new patInt(0); }\r
129     /** The maximum number of characters which\r
130         this pattern element can match. */\r
131     public patInt maxChars() { return new patInf(); }\r
132     /** return minimum number of characters in pattern */\r
133     public final patInt countMinChars() {\r
134         Pattern p = this;\r
135         patInt sum = new patInt(0);\r
136         while(p != null) {\r
137             sum.pluseq(p.minChars());\r
138             p = p.next;\r
139         }\r
140         return sum;\r
141     }\r
142     /** return maximum number of characters in pattern */\r
143     public final patInt countMaxChars() {\r
144         Pattern p = this;\r
145         patInt sum = new patInt(0);\r
146         while(p != null) {\r
147             sum.pluseq(p.maxChars());\r
148             p = p.next;\r
149         }\r
150         return sum;\r
151     }\r
152 \r
153     // This method is only needed by Multi_stage2 so far...\r
154     // the reason is that it may try something else after a\r
155     // match succeeds.  OrMark will only record the last thing\r
156     // tried in marks, so we need to backup the result of the\r
157     // last successful match and restore it if the next one\r
158     // does not succeed.\r
159     final int testMatch(Pattern p,int pos,Pthings pt) {\r
160         int[] tab = null;\r
161         if(pt.marks != null) try {\r
162                 tab = new int[pt.marks.length];\r
163                 for(int i=0;i<tab.length;i++)\r
164                     tab[i] = pt.marks[i];\r
165             } catch(Throwable t) {}\r
166         int ret = p.matchInternal(pos,pt);\r
167         if(ret < 0) pt.marks = tab;\r
168         return ret;\r
169     }\r
170 \r
171     /** Clones this pattern elements without cloning others in the\r
172         linked list. */\r
173     Pattern clone1(Hashtable h) {\r
174         throw new Error("No such method as clone1 for "+getClass().getName());\r
175     }\r
176     Pattern clone(Hashtable h) {\r
177         Pattern p = (Pattern)h.get(this);\r
178         if(p != null) {\r
179             return p;\r
180         }\r
181         p=clone1(h);\r
182         if(p==null)throw new Error("Null from clone1!");\r
183         h.put(this,p);\r
184         h.put(p,p);\r
185         if(next != null) p.next = next.clone(h);\r
186         if(parent != null) p.parent = parent.clone(h);\r
187         return p;\r
188     }\r
189     public boolean equals(Object o) {\r
190         return o == this;\r
191     }\r
192 };\r
193 \r