Copyright test
[jalview.git] / src / com / stevesoft / pat / Skip.java
1 /*******************************************************************************
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $(date) The Jalview Authors
4  *
5  * This file is part of Jalview.
6  *  
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *   
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  *******************************************************************************/
21 //
22 // This software is now distributed according to
23 // the Lesser Gnu Public License.  Please see
24 // http://www.gnu.org/copyleft/lesser.txt for
25 // the details.
26 //    -- Happy Computing!
27 //
28 package com.stevesoft.pat;
29
30 /**
31  * This class is used internally to search ahead for some optimized Regex
32  * objects. It searches within a String for occrences of a given String -- like
33  * a more flexible version of String.indexOf.
34  * 
35  * @see com.stevesoft.pat.Skip2
36  * @see com.stevesoft.pat.SkipBMH
37  */
38 public class Skip
39 {
40   static int mkmask(int c)
41   {
42     char x = (char) c;
43     return ~(CaseMgr.toUpperCase(x) | CaseMgr.toLowerCase(x) | CaseMgr
44             .toTitleCase(x));
45   }
46
47   String src;
48
49   int c, mask;
50
51   int offset;
52
53   boolean ign, m1;
54
55   /**
56    * Examine a Regex to determine what String it will attempt to skip to when
57    * searching for patterns. Return -1 if we aren't doing this.
58    */
59   public static String string(Regex r)
60   {
61     return r.skipper == null ? null : r.skipper.src;
62   }
63
64   /**
65    * Determine the offset of the String within the pattern that we are skipping
66    * to. Return -1 if we aren't doing this.
67    */
68   public static int offset(Regex r)
69   {
70     return r.skipper == null ? -1 : r.skipper.offset;
71   }
72
73   /**
74    * Initialize, give it a String to search for, tell it whether or not to
75    * ignoreCase, and what the offset is of the String within the String to be
76    * searched.
77    */
78   public Skip(String s, boolean ign, int o)
79   {
80     src = s;
81     c = s.charAt(0);
82     if (ign)
83     {
84       mask = mkmask(c);
85     }
86     else
87     {
88       mask = 0;
89     }
90     offset = o;
91     this.ign = ign;
92     m1 = (s.length() == 1);
93   }
94
95   /** The same as find(s,0,s.length()) */
96   public final int find(StringLike s)
97   {
98     return find(s, 0, s.length());
99   }
100
101   static final int min(int a, int b)
102   {
103     return a < b ? a : b;
104   }
105
106   /**
107    * Searches a given region of text beginning at position start and ending at
108    * position end for the skip object.
109    */
110   public int find(StringLike s, int start, int end)
111   {
112     if (start > end)
113     {
114       return -1;
115     }
116     start += offset;
117     int vend = min(s.length() - 1, end + offset);
118     if (mask != c)
119     {
120       for (int i = start; i <= vend; i++)
121       {
122         if (0 == (s.charAt(i) & mask))
123         {
124           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
125           if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
126           {
127             return i - offset;
128           }
129         }
130       }
131     }
132     else
133     {
134       for (int i = start; i <= vend; i++)
135       {
136         if (c == s.charAt(i))
137         {
138           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
139           if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
140           {
141             return i - offset;
142           }
143         }
144       }
145     }
146     return -1;
147   }
148
149   static Skip findSkip(Regex r)
150   {
151     return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes);
152   }
153
154   // look for things that can be skipped
155   static Skip findSkip(Pattern p, boolean ignoreCase, boolean trnc)
156   {
157     StringBuffer sb = new StringBuffer();
158     Skip subsk = null;
159     int offset = 0;
160     int skipc = -1, skipoff = 0;
161     for (; p != null; p = p.next)
162     {
163       if (p instanceof oneChar)
164       {
165         skipc = ((oneChar) p).c;
166         skipoff = offset;
167       }
168       if (p instanceof oneChar && p.next instanceof oneChar)
169       {
170         Pattern psav = p;
171         sb.append(((oneChar) p).c);
172         while (p.next instanceof oneChar)
173         {
174           sb.append(((oneChar) p.next).c);
175           p = p.next;
176         }
177         String st = sb.toString();
178         Skip sk = null;
179         if (st.length() > 2)
180         {
181           sk = new SkipBMH(st, ignoreCase, offset);
182         }
183         else
184         {
185           sk = new Skip2(st, ignoreCase, offset);
186         }
187         if (trnc && st.length() > 2)
188         { // chop out a whole string...
189           psav.next = new Skipped(st.substring(1));
190           psav.next.next = p.next;
191           psav.next.parent = p.parent;
192         }
193         return sk;
194       }
195       else if (p instanceof Or
196               && ((Or) p).v.size() == 1
197               && !((Or) p).leftForm().equals("(?!")
198               && null != (subsk = findSkip(
199                       (Pattern) ((Or) p).v.elementAt(0), ignoreCase, trnc)))
200       {
201         subsk.offset += offset;
202         return subsk;
203       }
204       else if (p.minChars().equals(p.maxChars()))
205       {
206         offset += p.minChars().intValue();
207       }
208       else
209       {
210         return skipc < 0 ? null : new Skip("" + (char) skipc, ignoreCase,
211                 skipoff);
212       }
213     }
214     return null;
215   }
216 }