001/*
002 *  gnu/regexp/RETokenOneOf.java
003 *  Copyright (C) 1998-2001 Wes Biggs
004 *
005 *  This library is free software; you can redistribute it and/or modify
006 *  it under the terms of the GNU Lesser General Public License as published
007 *  by the Free Software Foundation; either version 2.1 of the License, or
008 *  (at your option) any later version.
009 *
010 *  This library is distributed in the hope that it will be useful,
011 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
012 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 *  GNU Lesser General Public License for more details.
014 *
015 *  You should have received a copy of the GNU Lesser General Public License
016 *  along with this program; if not, write to the Free Software
017 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
018 */
019
020package gnu.regexp;
021import java.util.Vector;
022
023final class RETokenOneOf extends REToken {
024  private Vector options;
025  private boolean negative;
026
027  // This constructor is used for convenience when we know the set beforehand,
028  // e.g. \d --> new RETokenOneOf("0123456789",false, ..)
029  //      \D --> new RETokenOneOf("0123456789",true, ..)
030
031  RETokenOneOf(int subIndex, String optionsStr, boolean negative, boolean insens) {
032    super(subIndex);
033    options = new Vector();
034    this.negative = negative;
035    for (int i = 0; i < optionsStr.length(); i++)
036      options.addElement(new RETokenChar(subIndex,optionsStr.charAt(i),insens));
037  }
038
039  RETokenOneOf(int subIndex, Vector options, boolean negative) {
040    super(subIndex);
041    this.options = options;
042    this.negative = negative;
043  }
044
045  int getMinimumLength() {
046    int min = Integer.MAX_VALUE;
047    int x;
048    for (int i=0; i < options.size(); i++) {
049      if ((x = ((REToken) options.elementAt(i)).getMinimumLength()) < min)
050        min = x;
051    }
052    return min;
053  }
054
055    boolean match(CharIndexed input, REMatch mymatch) {
056    if (negative && (input.charAt(mymatch.index) == CharIndexed.OUT_OF_BOUNDS)) 
057      return false;
058
059    REMatch newMatch = null;
060    REMatch last = null;
061    REToken tk;
062    boolean isMatch;
063    for (int i=0; i < options.size(); i++) {
064        tk = (REToken) options.elementAt(i);
065        REMatch tryMatch = (REMatch) mymatch.clone();
066        if (tk.match(input, tryMatch)) { // match was successful
067            if (negative) return false;
068
069            if (next(input, tryMatch)) {
070                // Add tryMatch to list of possibilities.
071                if (last == null) {
072                    newMatch = tryMatch;
073                    last = tryMatch;
074                } else {
075                    last.next = tryMatch;
076                    last = tryMatch;
077                }
078            } // next succeeds
079        } // is a match
080    } // try next option
081
082    if (newMatch != null) {
083        if (negative) {
084            return false;
085        } else {
086            // set contents of mymatch equal to newMatch
087
088            // try each one that matched
089            mymatch.assignFrom(newMatch);
090            return true;
091        }
092    } else {
093        if (negative) {
094            ++mymatch.index;
095            return next(input, mymatch);
096        } else {
097            return false;
098        }
099    }
100
101    // index+1 works for [^abc] lists, not for generic lookahead (--> index)
102  }
103
104  void dump(StringBuffer os) {
105    os.append(negative ? "[^" : "(?:");
106    for (int i = 0; i < options.size(); i++) {
107      if (!negative && (i > 0)) os.append('|');
108      ((REToken) options.elementAt(i)).dumpAll(os);
109    }
110    os.append(negative ? ']' : ')');
111  }  
112}