001: /*****************************************************************************
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is the CVS Client Library.
027: * The Initial Developer of the Original Software is Thomas Singer.
028: * Portions created by Thomas Singer Copyright (C) 2001.
029: * All Rights Reserved.
030: *
031: * If you wish your version of this file to be governed by only the CDDL
032: * or only the GPL Version 2, indicate your decision by adding
033: * "[Contributor] elects to include this software in this distribution
034: * under the [CDDL or GPL Version 2] license." If you do not indicate a
035: * single choice of license, a recipient has the option to distribute
036: * your version of this file under either the CDDL, the GPL Version 2 or
037: * to extend the choice of license to its licensees as provided above.
038: * However, if you add GPL Version 2 code and therefore, elected the GPL
039: * Version 2 license, then the option applies only if the new code is
040: * made subject to such option by the copyright holder.
041: *
042: * Contributor(s): Thomas Singer, Milos Kleint
043: *****************************************************************************/package org.netbeans.lib.cvsclient.util;
044:
045: import java.util.*;
046:
047: /**
048: * @author Thomas Singer
049: */
050: public class SimpleStringPattern implements StringPattern {
051:
052: private static final char MATCH_EACH = '*';
053: private static final char MATCH_ONE = '?';
054:
055: private final List subPatterns = new LinkedList();
056:
057: /**
058: * Creates a SimpleStringPattern for the specified definition.
059: * The definition might contain two special characters ('*' and '?').
060: */
061: public SimpleStringPattern(String definition) {
062: splitInSubPattern(definition);
063: }
064:
065: /**
066: * Returns whether the specified string matches thiz pattern.
067: */
068: public boolean doesMatch(String string) {
069: int index = 0;
070: SubPattern subPattern = null;
071: for (Iterator it = subPatterns.iterator(); it.hasNext();) {
072: subPattern = (SubPattern) it.next();
073: index = subPattern.doesMatch(string, index);
074: if (index < 0) {
075: return false;
076: }
077: }
078:
079: if (index == string.length()) {
080: return true;
081: }
082: if (subPattern == null) {
083: return false;
084: }
085: return subPattern.checkEnding(string, index);
086: }
087:
088: private void splitInSubPattern(String definition) {
089: char prevSubPattern = ' ';
090:
091: int prevIndex = 0;
092: for (int index = 0; index >= 0;) {
093: prevIndex = index;
094:
095: index = definition.indexOf(MATCH_EACH, prevIndex);
096: if (index >= 0) {
097: String match = definition.substring(prevIndex, index);
098: addSubPattern(match, prevSubPattern);
099: prevSubPattern = MATCH_EACH;
100: index++;
101: continue;
102: }
103: index = definition.indexOf(MATCH_ONE, prevIndex);
104: if (index >= 0) {
105: String match = definition.substring(prevIndex, index);
106: addSubPattern(match, prevSubPattern);
107: prevSubPattern = MATCH_ONE;
108: index++;
109: continue;
110: }
111: }
112: String match = definition.substring(prevIndex);
113: addSubPattern(match, prevSubPattern);
114: }
115:
116: private void addSubPattern(String match, char subPatternMode) {
117: SubPattern subPattern = null;
118: switch (subPatternMode) {
119: case MATCH_EACH:
120: subPattern = new MatchEachCharPattern(match);
121: break;
122: case MATCH_ONE:
123: subPattern = new MatchOneCharPattern(match);
124: break;
125: default:
126: subPattern = new MatchExactSubPattern(match);
127: break;
128: }
129:
130: subPatterns.add(subPattern);
131: }
132:
133: public String toString() {
134: StringBuffer buffer = new StringBuffer();
135: for (Iterator it = subPatterns.iterator(); it.hasNext();) {
136: SubPattern subPattern = (SubPattern) it.next();
137: buffer.append(subPattern.toString());
138: }
139: return buffer.toString();
140: }
141:
142: public boolean equals(Object obj) {
143: if (!(obj instanceof SimpleStringPattern))
144: return false;
145: return subPatterns
146: .equals(((SimpleStringPattern) obj).subPatterns);
147: }
148:
149: public int hashCode() {
150: return -subPatterns.hashCode();
151: }
152:
153: public static void main(String[] arguments) {
154: StringPattern sp = new SimpleStringPattern("a*b"); //NOI18N
155:
156: test(sp, "ab", true); //NOI18N
157: test(sp, "aab", true); //NOI18N
158: test(sp, "ba", false); //NOI18N
159: test(sp, "abc", false); //NOI18N
160:
161: sp = new SimpleStringPattern("*.txt"); //NOI18N
162:
163: test(sp, "datei.txt", true); //NOI18N
164: test(sp, ".txt", true); //NOI18N
165: test(sp, "datei.tx", false); //NOI18N
166: test(sp, "datei.txt.txt", true); //NOI18N
167:
168: sp = new SimpleStringPattern("datei*1*"); //NOI18N
169:
170: test(sp, "datei0.txt", false); //NOI18N
171: test(sp, "datei1.txt", true); //NOI18N
172: test(sp, "datei.tx", false); //NOI18N
173: test(sp, "datei1.txt.txt", true); //NOI18N
174:
175: sp = new SimpleStringPattern("Makefile"); //NOI18N
176:
177: test(sp, "Makefile", true); //NOI18N
178: test(sp, "Makefile.mak", false); //NOI18N
179: test(sp, "Makefile1", false); //NOI18N
180: test(sp, ".Makefile", false); //NOI18N
181: test(sp, ".Makefile.", false); //NOI18N
182:
183: sp = new SimpleStringPattern("*~"); //NOI18N
184:
185: test(sp, "datei~", true); //NOI18N
186: test(sp, "datei~1", false); //NOI18N
187: test(sp, "datei~1~", true); //NOI18N
188:
189: // Equality:
190: SimpleStringPattern pattern1 = new SimpleStringPattern(
191: "*.class");
192: SimpleStringPattern pattern2 = new SimpleStringPattern(
193: "*.class");
194: System.err.println(pattern1 + ".equals(" + pattern2 + ") = "
195: + pattern1.equals(pattern2));
196:
197: pattern1 = new SimpleStringPattern("?.class");
198: pattern2 = new SimpleStringPattern("*.class");
199: System.err.println(pattern1 + ".equals(" + pattern2 + ") = "
200: + pattern1.equals(pattern2));
201:
202: pattern1 = new SimpleStringPattern("*.clazz");
203: pattern2 = new SimpleStringPattern("*.class");
204: System.err.println(pattern1 + ".equals(" + pattern2 + ") = "
205: + pattern1.equals(pattern2));
206: }
207:
208: private static void test(StringPattern sp, String testString,
209: boolean shouldResult) {
210: System.err.print('"' + sp.toString() + '"' + ": " + testString
211: + " " + shouldResult); //NOI18N
212:
213: boolean doesMatch = sp.doesMatch(testString);
214:
215: if (doesMatch == shouldResult) {
216: System.err.println(" proved"); //NOI18N
217: } else {
218: System.err.println(" **denied**"); //NOI18N
219: }
220: }
221:
222: private static abstract class SubPattern {
223: protected final String match;
224:
225: protected SubPattern(String match) {
226: this .match = match;
227: }
228:
229: /**
230: * @parameter string ... the whole string to test for matching
231: * @parameter index ... the index in string where this' test should begin
232: * @returns ... if successful the next test-position, if not -1
233: */
234: public abstract int doesMatch(String string, int index);
235:
236: public boolean checkEnding(String string, int index) {
237: return false;
238: }
239:
240: public boolean equals(Object obj) {
241: if (!(this .getClass().isInstance(obj)))
242: return false;
243: return match.equals(((SubPattern) obj).match);
244: }
245:
246: public int hashCode() {
247: return -match.hashCode();
248: }
249: }
250:
251: private static class MatchExactSubPattern extends SubPattern {
252: public MatchExactSubPattern(String match) {
253: super (match);
254: }
255:
256: public int doesMatch(String string, int index) {
257: if (!string.startsWith(match, index)) {
258: return -1;
259: }
260: return index + match.length();
261: }
262:
263: public String toString() {
264: return match;
265: }
266: }
267:
268: private static class MatchEachCharPattern extends SubPattern {
269: public MatchEachCharPattern(String match) {
270: super (match);
271: }
272:
273: public int doesMatch(String string, int index) {
274: int matchIndex = string.indexOf(match, index);
275: if (matchIndex < 0) {
276: return -1;
277: }
278: return matchIndex + match.length();
279: }
280:
281: public boolean checkEnding(String string, int index) {
282: return string.endsWith(match);
283: }
284:
285: public String toString() {
286: return MATCH_EACH + match;
287: }
288: }
289:
290: private static class MatchOneCharPattern extends
291: MatchExactSubPattern {
292: public MatchOneCharPattern(String match) {
293: super (match);
294: }
295:
296: public int doesMatch(String string, int index) {
297: index++;
298: if (string.length() < index) {
299: return -1;
300: }
301: return super .doesMatch(string, index);
302: }
303:
304: public String toString() {
305: return MATCH_ONE + match;
306: }
307: }
308: }
|