JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / com / stevesoft / pat / Skip.java
1 //
2 // This software is now distributed according to
3 // the Lesser Gnu Public License.  Please see
4 // http://www.gnu.org/copyleft/lesser.txt for
5 // the details.
6 //    -- Happy Computing!
7 //
8 package com.stevesoft.pat;
9
10 /**
11  * This class is used internally to search ahead for some optimized Regex
12  * objects. It searches within a String for occrences of a given String -- like
13  * a more flexible version of String.indexOf.
14  * 
15  * @see com.stevesoft.pat.Skip2
16  * @see com.stevesoft.pat.SkipBMH
17  */
18 public class Skip
19 {
20   static int mkmask(int c)
21   {
22     char x = (char) c;
23     return ~(CaseMgr.toUpperCaseC(x) | CaseMgr.toLowerCaseC(x) | CaseMgr
24             .toTitleCaseC(x));
25   }
26
27   String src;
28
29   int c, mask;
30
31   int offset;
32
33   boolean ign, m1;
34
35   /**
36    * Examine a Regex to determine what String it will attempt to skip to when
37    * searching for patterns. Return -1 if we aren't doing this.
38    */
39   public static String string(Regex r)
40   {
41     return r.skipper == null ? null : r.skipper.src;
42   }
43
44   /**
45    * Determine the offset of the String within the pattern that we are skipping
46    * to. Return -1 if we aren't doing this.
47    */
48   public static int offset(Regex r)
49   {
50     return r.skipper == null ? -1 : r.skipper.offset;
51   }
52
53   /**
54    * Initialize, give it a String to search for, tell it whether or not to
55    * ignoreCase, and what the offset is of the String within the String to be
56    * searched.
57    */
58   public Skip(String s, boolean ign, int o)
59   {
60     src = s;
61     c = s.charAt(0);
62     if (ign)
63     {
64       mask = mkmask(c);
65     }
66     else
67     {
68       mask = 0;
69     }
70     offset = o;
71     this.ign = ign;
72     m1 = (s.length() == 1);
73   }
74
75   /** The same as find(s,0,s.length()) */
76   public final int find(StringLike s)
77   {
78     return find(s, 0, s.length());
79   }
80
81   static final int min(int a, int b)
82   {
83     return a < b ? a : b;
84   }
85
86   /**
87    * Searches a given region of text beginning at position start and ending at
88    * position end for the skip object.
89    */
90   public int find(StringLike s, int start, int end)
91   {
92     if (start > end)
93     {
94       return -1;
95     }
96     start += offset;
97     int vend = min(s.length() - 1, end + offset);
98     if (mask != c)
99     {
100       for (int i = start; i <= vend; i++)
101       {
102         if (0 == (s.charAt(i) & mask))
103         {
104           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
105           if (m1 || CaseMgr.regionMatchesLike2(s, ign, i, src, 0, src.length()))
106           {
107             return i - offset;
108           }
109         }
110       }
111     }
112     else
113     {
114       for (int i = start; i <= vend; i++)
115       {
116         if (c == s.charAt(i))
117         {
118           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
119           if (m1 || CaseMgr.regionMatchesLike2(s, ign, i, src, 0, src.length()))
120           {
121             return i - offset;
122           }
123         }
124       }
125     }
126     return -1;
127   }
128
129   static Skip findSkipRegex(Regex r)
130   {
131     return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes);
132   }
133
134   // look for things that can be skipped
135   static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc)
136   {
137     StringBuffer sb = new StringBuffer();
138     Skip subsk = null;
139     int offset = 0;
140     int skipc = -1, skipoff = 0;
141     for (; p != null; p = p.next)
142     {
143       if (p instanceof oneChar)
144       {
145         skipc = ((oneChar) p).c;
146         skipoff = offset;
147       }
148       if (p instanceof oneChar && p.next instanceof oneChar)
149       {
150         Pattern psav = p;
151         sb.append(((oneChar) p).c);
152         while (p.next instanceof oneChar)
153         {
154           sb.append(((oneChar) p.next).c);
155           p = p.next;
156         }
157         String st = sb.toString();
158         Skip sk = null;
159         if (st.length() > 2)
160         {
161           sk = new SkipBMH(st, ignoreCase, offset);
162         }
163         else
164         {
165           sk = new Skip2(st, ignoreCase, offset);
166         }
167         if (trnc && st.length() > 2)
168         { // chop out a whole string...
169           psav.next = new Skipped(st.substring(1));
170           psav.next.next = p.next;
171           psav.next.parent = p.parent;
172         }
173         return sk;
174       }
175       else if (p instanceof Or
176               && ((Or) p).v.size() == 1
177               && !((Or) p).leftForm().equals("(?!")
178               && null != (subsk = findSkip((Pattern) ((Or) p).v
179                       .elementAt(0), ignoreCase, trnc)))
180       {
181         subsk.offset += offset;
182         return subsk;
183       }
184       else if (p.minChars().equals(p.maxChars()))
185       {
186         offset += p.minChars().intValue();
187       }
188       else
189       {
190         return skipc < 0 ? null : new Skip("" + (char) skipc, ignoreCase,
191                 skipoff);
192       }
193     }
194     return null;
195   }
196 }