001: /*
002: *
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
004: *
005: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
006: *
007: * The contents of this file are subject to the terms of either the GNU
008: * General Public License Version 2 only ("GPL") or the Common
009: * Development and Distribution License("CDDL") (collectively, the
010: * "License"). You may not use this file except in compliance with the
011: * License. You can obtain a copy of the License at
012: * http://www.netbeans.org/cddl-gplv2.html
013: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
014: * specific language governing permissions and limitations under the
015: * License. When distributing the software, include this License Header
016: * Notice in each file and include the License file at
017: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
018: * particular file as subject to the "Classpath" exception as provided
019: * by Sun in the GPL Version 2 section of the License file that
020: * accompanied this code. If applicable, add the following below the
021: * License Header, with the fields enclosed by brackets [] replaced by
022: * your own identifying information:
023: * "Portions Copyrighted [year] [name of copyright owner]"
024: *
025: * Contributor(s):
026: *
027: * The Original Software is NetBeans. The Initial Developer of the Original
028: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
029: * Microsystems, Inc. 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: /*
043: * PatternUtilities.java
044: *
045: * Created on April 26, 2001, 5:11 PM
046: */
047:
048: package org.netbeans.xtest.testrunner;
049:
050: import java.io.File;
051: import java.util.Vector;
052: import java.util.StringTokenizer;
053:
054: /**
055: *
056: * @author vs124454
057: * @version
058: */
059: public class PatternUtilities {
060:
061: /** Creates new PatternUtilities */
062: private PatternUtilities() {
063: }
064:
065: /**
066: * Does the path match the start of this pattern up to the first "**".
067: +
068: * <p>This is not a general purpose test and should only be used if you
069: * can live with false positives.</p>
070: *
071: * <p><code>pattern=**\\a</code> and <code>str=b</code> will yield true.
072: *
073: * @param pattern the (non-null) pattern to match against
074: * @param str the (non-null) string (path) to match
075: */
076: public static boolean matchPatternStart(String pattern, String str) {
077: // When str starts with a File.separator, pattern has to start with a
078: // File.separator.
079: // When pattern starts with a File.separator, str has to start with a
080: // File.separator.
081: if (str.startsWith(File.separator) != pattern
082: .startsWith(File.separator)) {
083: return false;
084: }
085:
086: Vector patDirs = new Vector();
087: StringTokenizer st = new StringTokenizer(pattern,
088: File.separator);
089: while (st.hasMoreTokens()) {
090: patDirs.addElement(st.nextToken());
091: }
092:
093: Vector strDirs = new Vector();
094: st = new StringTokenizer(str, File.separator);
095: while (st.hasMoreTokens()) {
096: strDirs.addElement(st.nextToken());
097: }
098:
099: int patIdxStart = 0;
100: int patIdxEnd = patDirs.size() - 1;
101: int strIdxStart = 0;
102: int strIdxEnd = strDirs.size() - 1;
103:
104: // up to first '**'
105: while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
106: String patDir = (String) patDirs.elementAt(patIdxStart);
107: if (patDir.equals("**")) {
108: break;
109: }
110: if (!match(patDir, (String) strDirs.elementAt(strIdxStart))) {
111: return false;
112: }
113: patIdxStart++;
114: strIdxStart++;
115: }
116:
117: if (strIdxStart > strIdxEnd) {
118: // String is exhausted
119: return true;
120: } else if (patIdxStart > patIdxEnd) {
121: // String not exhausted, but pattern is. Failure.
122: return false;
123: } else {
124: // pattern now holds ** while string is not exhausted
125: // this will generate false positives but we can live with that.
126: return true;
127: }
128: }
129:
130: /**
131: * Matches a path against a pattern.
132: *
133: * @param pattern the (non-null) pattern to match against
134: * @param str the (non-null) string (path) to match
135: *
136: * @return <code>true</code> when the pattern matches against the string.
137: * <code>false</code> otherwise.
138: */
139: public static boolean matchPath(String pattern, String str) {
140: // When str starts with a File.separator, pattern has to start with a
141: // File.separator.
142: // When pattern starts with a File.separator, str has to start with a
143: // File.separator.
144: if (str.startsWith(File.separator) != pattern
145: .startsWith(File.separator)) {
146: return false;
147: }
148:
149: Vector patDirs = new Vector();
150: StringTokenizer st = new StringTokenizer(pattern,
151: File.separator);
152: while (st.hasMoreTokens()) {
153: patDirs.addElement(st.nextToken());
154: }
155:
156: Vector strDirs = new Vector();
157: st = new StringTokenizer(str, File.separator);
158: while (st.hasMoreTokens()) {
159: strDirs.addElement(st.nextToken());
160: }
161:
162: int patIdxStart = 0;
163: int patIdxEnd = patDirs.size() - 1;
164: int strIdxStart = 0;
165: int strIdxEnd = strDirs.size() - 1;
166:
167: // up to first '**'
168: while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
169: String patDir = (String) patDirs.elementAt(patIdxStart);
170: if (patDir.equals("**")) {
171: break;
172: }
173: if (!match(patDir, (String) strDirs.elementAt(strIdxStart))) {
174: return false;
175: }
176: patIdxStart++;
177: strIdxStart++;
178: }
179: if (strIdxStart > strIdxEnd) {
180: // String is exhausted
181: for (int i = patIdxStart; i <= patIdxEnd; i++) {
182: if (!patDirs.elementAt(i).equals("**")) {
183: return false;
184: }
185: }
186: return true;
187: } else {
188: if (patIdxStart > patIdxEnd) {
189: // String not exhausted, but pattern is. Failure.
190: return false;
191: }
192: }
193:
194: // up to last '**'
195: while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
196: String patDir = (String) patDirs.elementAt(patIdxEnd);
197: if (patDir.equals("**")) {
198: break;
199: }
200: if (!match(patDir, (String) strDirs.elementAt(strIdxEnd))) {
201: return false;
202: }
203: patIdxEnd--;
204: strIdxEnd--;
205: }
206: if (strIdxStart > strIdxEnd) {
207: // String is exhausted
208: for (int i = patIdxStart; i <= patIdxEnd; i++) {
209: if (!patDirs.elementAt(i).equals("**")) {
210: return false;
211: }
212: }
213: return true;
214: }
215:
216: while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
217: int patIdxTmp = -1;
218: for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
219: if (patDirs.elementAt(i).equals("**")) {
220: patIdxTmp = i;
221: break;
222: }
223: }
224: if (patIdxTmp == patIdxStart + 1) {
225: // '**/**' situation, so skip one
226: patIdxStart++;
227: continue;
228: }
229: // Find the pattern between padIdxStart & padIdxTmp in str between
230: // strIdxStart & strIdxEnd
231: int patLength = (patIdxTmp - patIdxStart - 1);
232: int strLength = (strIdxEnd - strIdxStart + 1);
233: int foundIdx = -1;
234: strLoop: for (int i = 0; i <= strLength - patLength; i++) {
235: for (int j = 0; j < patLength; j++) {
236: String subPat = (String) patDirs
237: .elementAt(patIdxStart + j + 1);
238: String subStr = (String) strDirs
239: .elementAt(strIdxStart + i + j);
240: if (!match(subPat, subStr)) {
241: continue strLoop;
242: }
243: }
244:
245: foundIdx = strIdxStart + i;
246: break;
247: }
248:
249: if (foundIdx == -1) {
250: return false;
251: }
252:
253: patIdxStart = patIdxTmp;
254: strIdxStart = foundIdx + patLength;
255: }
256:
257: for (int i = patIdxStart; i <= patIdxEnd; i++) {
258: if (!patDirs.elementAt(i).equals("**")) {
259: return false;
260: }
261: }
262:
263: return true;
264: }
265:
266: /**
267: * Matches a string against a pattern. The pattern contains two special
268: * characters:
269: * '*' which means zero or more characters,
270: * '?' which means one and only one character.
271: *
272: * @param pattern the (non-null) pattern to match against
273: * @param str the (non-null) string that must be matched against the
274: * pattern
275: *
276: * @return <code>true</code> when the string matches against the pattern,
277: * <code>false</code> otherwise.
278: */
279: public static boolean match(String pattern, String str) {
280: char[] patArr = pattern.toCharArray();
281: char[] strArr = str.toCharArray();
282: int patIdxStart = 0;
283: int patIdxEnd = patArr.length - 1;
284: int strIdxStart = 0;
285: int strIdxEnd = strArr.length - 1;
286: char ch;
287:
288: boolean containsStar = false;
289: for (int i = 0; i < patArr.length; i++) {
290: if (patArr[i] == '*') {
291: containsStar = true;
292: break;
293: }
294: }
295:
296: if (!containsStar) {
297: // No '*'s, so we make a shortcut
298: if (patIdxEnd != strIdxEnd) {
299: return false; // Pattern and string do not have the same size
300: }
301: for (int i = 0; i <= patIdxEnd; i++) {
302: ch = patArr[i];
303: if (ch != '?' && ch != strArr[i]) {
304: return false; // Character mismatch
305: }
306: }
307: return true; // String matches against pattern
308: }
309:
310: if (patIdxEnd == 0) {
311: return true; // Pattern contains only '*', which matches anything
312: }
313:
314: // Process characters before first star
315: while ((ch = patArr[patIdxStart]) != '*'
316: && strIdxStart <= strIdxEnd) {
317: if (ch != '?' && ch != strArr[strIdxStart]) {
318: return false;
319: }
320: patIdxStart++;
321: strIdxStart++;
322: }
323: if (strIdxStart > strIdxEnd) {
324: // All characters in the string are used. Check if only '*'s are
325: // left in the pattern. If so, we succeeded. Otherwise failure.
326: for (int i = patIdxStart; i <= patIdxEnd; i++) {
327: if (patArr[i] != '*') {
328: return false;
329: }
330: }
331: return true;
332: }
333:
334: // Process characters after last star
335: while ((ch = patArr[patIdxEnd]) != '*'
336: && strIdxStart <= strIdxEnd) {
337: if (ch != '?' && ch != strArr[strIdxEnd]) {
338: return false;
339: }
340: patIdxEnd--;
341: strIdxEnd--;
342: }
343: if (strIdxStart > strIdxEnd) {
344: // All characters in the string are used. Check if only '*'s are
345: // left in the pattern. If so, we succeeded. Otherwise failure.
346: for (int i = patIdxStart; i <= patIdxEnd; i++) {
347: if (patArr[i] != '*') {
348: return false;
349: }
350: }
351: return true;
352: }
353:
354: // process pattern between stars. padIdxStart and patIdxEnd point
355: // always to a '*'.
356: while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
357: int patIdxTmp = -1;
358: for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
359: if (patArr[i] == '*') {
360: patIdxTmp = i;
361: break;
362: }
363: }
364: if (patIdxTmp == patIdxStart + 1) {
365: // Two stars next to each other, skip the first one.
366: patIdxStart++;
367: continue;
368: }
369: // Find the pattern between padIdxStart & padIdxTmp in str between
370: // strIdxStart & strIdxEnd
371: int patLength = (patIdxTmp - patIdxStart - 1);
372: int strLength = (strIdxEnd - strIdxStart + 1);
373: int foundIdx = -1;
374: strLoop: for (int i = 0; i <= strLength - patLength; i++) {
375: for (int j = 0; j < patLength; j++) {
376: ch = patArr[patIdxStart + j + 1];
377: if (ch != '?' && ch != strArr[strIdxStart + i + j]) {
378: continue strLoop;
379: }
380: }
381:
382: foundIdx = strIdxStart + i;
383: break;
384: }
385:
386: if (foundIdx == -1) {
387: return false;
388: }
389:
390: patIdxStart = patIdxTmp;
391: strIdxStart = foundIdx + patLength;
392: }
393:
394: // All characters in the string are used. Check if only '*'s are left
395: // in the pattern. If so, we succeeded. Otherwise failure.
396: for (int i = patIdxStart; i <= patIdxEnd; i++) {
397: if (patArr[i] != '*') {
398: return false;
399: }
400: }
401: return true;
402: }
403: }
|