git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270840 13f79535-47bb-0310-9956-ffa450edef68master
@@ -22,6 +22,7 @@ import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.types.PatternSet; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Unzip a file. | |||
@@ -205,7 +206,7 @@ public class Expand extends MatchingTask | |||
{ | |||
for( int w = 0; w < incls.length; w++ ) | |||
{ | |||
boolean isIncl = DirectoryScanner.match( incls[ w ], name ); | |||
boolean isIncl = ScannerUtil.match( incls[ w ], name ); | |||
if( isIncl ) | |||
{ | |||
included = true; | |||
@@ -218,7 +219,7 @@ public class Expand extends MatchingTask | |||
{ | |||
for( int w = 0; w < excls.length; w++ ) | |||
{ | |||
boolean isExcl = DirectoryScanner.match( excls[ w ], name ); | |||
boolean isExcl = ScannerUtil.match( excls[ w ], name ); | |||
if( isExcl ) | |||
{ | |||
included = false; | |||
@@ -15,6 +15,7 @@ import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Class for scanning a Visual Age for Java workspace for packages matching a | |||
@@ -69,7 +70,7 @@ class VAJWorkspaceScanner extends DirectoryScanner | |||
*/ | |||
protected static boolean match( String pattern, String str ) | |||
{ | |||
return DirectoryScanner.match( pattern, str ); | |||
return ScannerUtil.match( pattern, str ); | |||
} | |||
/** | |||
@@ -18,6 +18,7 @@ import com.starbase.util.Platform; | |||
import java.util.StringTokenizer; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Checks out files from a specific StarTeam server, project, view, and folder. | |||
@@ -765,7 +766,7 @@ public class AntStarTeamCheckOut extends org.apache.tools.ant.Task | |||
StringTokenizer exStr = new StringTokenizer( patterns, " " ); | |||
while( exStr.hasMoreTokens() ) | |||
{ | |||
if( DirectoryScanner.match( exStr.nextToken(), pName ) ) | |||
if( ScannerUtil.match( exStr.nextToken(), pName ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -91,24 +91,6 @@ import org.apache.myrmidon.api.TaskException; | |||
public class DirectoryScanner | |||
implements FileScanner | |||
{ | |||
/** | |||
* Patterns that should be excluded by default. | |||
* | |||
* @see #addDefaultExcludes() | |||
*/ | |||
private final static String[] DEFAULTEXCLUDES = | |||
{ | |||
"**/*~", | |||
"**/#*#", | |||
"**/.#*", | |||
"**/%*%", | |||
"**/CVS", | |||
"**/CVS/**", | |||
"**/.cvsignore", | |||
"**/SCCS", | |||
"**/SCCS/**", | |||
"**/vssver.scc" | |||
}; | |||
/** | |||
* Have the ArrayLists holding our results been built by a slow scan? | |||
@@ -174,493 +156,6 @@ public class DirectoryScanner | |||
*/ | |||
private String[] m_includes; | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
public static boolean match( final String pattern, final String str ) | |||
{ | |||
return match( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @param isCaseSensitive Description of Parameter | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean match( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
char[] patArr = pattern.toCharArray(); | |||
char[] strArr = str.toCharArray(); | |||
int patIdxStart = 0; | |||
int patIdxEnd = patArr.length - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strArr.length - 1; | |||
char ch; | |||
boolean containsStar = false; | |||
for( int i = 0; i < patArr.length; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
containsStar = true; | |||
break; | |||
} | |||
} | |||
if( !containsStar ) | |||
{ | |||
// No '*'s, so we make a shortcut | |||
if( patIdxEnd != strIdxEnd ) | |||
{ | |||
return false;// Pattern and string do not have the same size | |||
} | |||
for( int i = 0; i <= patIdxEnd; i++ ) | |||
{ | |||
ch = patArr[ i ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ i ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ i ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
} | |||
return true;// String matches against pattern | |||
} | |||
if( patIdxEnd == 0 ) | |||
{ | |||
return true;// Pattern contains only '*', which matches anything | |||
} | |||
// Process characters before first star | |||
while( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// Process characters after last star | |||
while( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxEnd ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxEnd ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// process pattern between stars. padIdxStart and patIdxEnd point | |||
// always to a '*'. | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// Two stars next to each other, skip the first one. | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
ch = patArr[ patIdxStart + j + 1 ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart + i + j ] ) | |||
{ | |||
continue strLoop; | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart + i + j ] ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
// All characters in the string are used. Check if only '*'s are left | |||
// in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, final String str ) | |||
{ | |||
return matchPath( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must a case sensitive match be done? | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
} | |||
// up to last '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxEnd ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxEnd ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// '**/**' situation, so skip one | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
String subPat = (String)patDirs.get( patIdxStart + j + 1 ); | |||
String subStr = (String)strDirs.get( strIdxStart + i + j ); | |||
if( !match( subPat, subStr, isCaseSensitive ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, final String str ) | |||
{ | |||
return matchPatternStart( pattern, str, true ); | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must matches be case sensitive? | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
return true; | |||
} | |||
else if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
else | |||
{ | |||
// pattern now holds ** while string is not exhausted | |||
// this will generate false positives but we can live with that. | |||
return true; | |||
} | |||
} | |||
/** | |||
* Sets the basedir for scanning. This is the directory that is scanned | |||
* recursively. All '/' and '\' characters are replaced by <code>File.separatorChar</code> | |||
@@ -900,14 +395,14 @@ public class DirectoryScanner | |||
{ | |||
int excludesLength = m_excludes == null ? 0 : m_excludes.length; | |||
String[] newExcludes; | |||
newExcludes = new String[ excludesLength + DEFAULTEXCLUDES.length ]; | |||
newExcludes = new String[ excludesLength + ScannerUtil.DEFAULTEXCLUDES.length ]; | |||
if( excludesLength > 0 ) | |||
{ | |||
System.arraycopy( m_excludes, 0, newExcludes, 0, excludesLength ); | |||
} | |||
for( int i = 0; i < DEFAULTEXCLUDES.length; i++ ) | |||
for( int i = 0; i < ScannerUtil.DEFAULTEXCLUDES.length; i++ ) | |||
{ | |||
newExcludes[ i + excludesLength ] = DEFAULTEXCLUDES[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); | |||
newExcludes[ i + excludesLength ] = ScannerUtil.DEFAULTEXCLUDES[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); | |||
} | |||
m_excludes = newExcludes; | |||
} | |||
@@ -982,7 +477,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_excludes.length; i++ ) | |||
{ | |||
if( matchPath( m_excludes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPath( m_excludes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1001,7 +496,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_includes.length; i++ ) | |||
{ | |||
if( matchPath( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPath( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1020,7 +515,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_includes.length; i++ ) | |||
{ | |||
if( matchPatternStart( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPatternStart( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1166,11 +661,6 @@ public class DirectoryScanner | |||
m_haveSlowResults = true; | |||
} | |||
public static String[] getDEFAULTEXCLUDES() | |||
{ | |||
return DEFAULTEXCLUDES; | |||
} | |||
public ArrayList getDirsExcluded() | |||
{ | |||
return m_dirsExcluded; | |||
@@ -13,23 +13,18 @@ import java.util.StringTokenizer; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.framework.Pattern; | |||
import org.apache.tools.ant.ProjectComponent; | |||
/** | |||
* Named collection of include/exclude tags. <p> | |||
* | |||
* Moved out of MatchingTask to make it a standalone object that could be | |||
* referenced (by scripts for example). | |||
* | |||
* @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a> | |||
* @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
* stefano@apache.org</a> | |||
* @author Sam Ruby <a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a> | |||
* @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
* @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a> | |||
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a> | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
*/ | |||
public class PatternSet | |||
extends ProjectComponent | |||
{ | |||
private ArrayList m_includeList = new ArrayList(); | |||
private ArrayList m_excludeList = new ArrayList(); | |||
@@ -106,8 +101,8 @@ public class PatternSet | |||
public String toString() | |||
{ | |||
return "patternSet{ includes: " + m_includeList + | |||
" excludes: " + m_excludeList + " }"; | |||
return "PatternSet [ includes: " + m_includeList + | |||
" excludes: " + m_excludeList + " ]"; | |||
} | |||
private Pattern[] parsePatterns( final String patternString ) | |||
@@ -0,0 +1,525 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.tools.ant.types; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.StringTokenizer; | |||
/** | |||
* | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ScannerUtil | |||
{ | |||
/** | |||
* Patterns that should be excluded by default. | |||
*/ | |||
public final static String[] DEFAULTEXCLUDES = new String[] | |||
{ | |||
"**/*~", | |||
"**/#*#", | |||
"**/.#*", | |||
"**/%*%", | |||
"**/CVS", | |||
"**/CVS/**", | |||
"**/.cvsignore", | |||
"**/SCCS", | |||
"**/SCCS/**", | |||
"**/vssver.scc" | |||
}; | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
public static boolean match( final String pattern, final String str ) | |||
{ | |||
return match( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @param isCaseSensitive Description of Parameter | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean match( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
char[] patArr = pattern.toCharArray(); | |||
char[] strArr = str.toCharArray(); | |||
int patIdxStart = 0; | |||
int patIdxEnd = patArr.length - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strArr.length - 1; | |||
char ch; | |||
boolean containsStar = false; | |||
for( int i = 0; i < patArr.length; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
containsStar = true; | |||
break; | |||
} | |||
} | |||
if( !containsStar ) | |||
{ | |||
// No '*'s, so we make a shortcut | |||
if( patIdxEnd != strIdxEnd ) | |||
{ | |||
return false;// Pattern and string do not have the same size | |||
} | |||
for( int i = 0; i <= patIdxEnd; i++ ) | |||
{ | |||
ch = patArr[ i ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ i ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ i ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
} | |||
return true;// String matches against pattern | |||
} | |||
if( patIdxEnd == 0 ) | |||
{ | |||
return true;// Pattern contains only '*', which matches anything | |||
} | |||
// Process characters before first star | |||
while( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// Process characters after last star | |||
while( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxEnd ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxEnd ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// process pattern between stars. padIdxStart and patIdxEnd point | |||
// always to a '*'. | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// Two stars next to each other, skip the first one. | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
ch = patArr[ patIdxStart + j + 1 ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart + i + j ] ) | |||
{ | |||
continue strLoop; | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart + i + j ] ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
// All characters in the string are used. Check if only '*'s are left | |||
// in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, final String str ) | |||
{ | |||
return matchPath( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must a case sensitive match be done? | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
} | |||
// up to last '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxEnd ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxEnd ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// '**/**' situation, so skip one | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
String subPat = (String)patDirs.get( patIdxStart + j + 1 ); | |||
String subStr = (String)strDirs.get( strIdxStart + i + j ); | |||
if( !match( subPat, subStr, isCaseSensitive ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, final String str ) | |||
{ | |||
return matchPatternStart( pattern, str, true ); | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must matches be case sensitive? | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
return true; | |||
} | |||
else if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
else | |||
{ | |||
// pattern now holds ** while string is not exhausted | |||
// this will generate false positives but we can live with that. | |||
return true; | |||
} | |||
} | |||
} |
@@ -22,6 +22,7 @@ import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.types.PatternSet; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Unzip a file. | |||
@@ -205,7 +206,7 @@ public class Expand extends MatchingTask | |||
{ | |||
for( int w = 0; w < incls.length; w++ ) | |||
{ | |||
boolean isIncl = DirectoryScanner.match( incls[ w ], name ); | |||
boolean isIncl = ScannerUtil.match( incls[ w ], name ); | |||
if( isIncl ) | |||
{ | |||
included = true; | |||
@@ -218,7 +219,7 @@ public class Expand extends MatchingTask | |||
{ | |||
for( int w = 0; w < excls.length; w++ ) | |||
{ | |||
boolean isExcl = DirectoryScanner.match( excls[ w ], name ); | |||
boolean isExcl = ScannerUtil.match( excls[ w ], name ); | |||
if( isExcl ) | |||
{ | |||
included = false; | |||
@@ -15,6 +15,7 @@ import java.util.ArrayList; | |||
import java.util.Iterator; | |||
import java.util.StringTokenizer; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Class for scanning a Visual Age for Java workspace for packages matching a | |||
@@ -69,7 +70,7 @@ class VAJWorkspaceScanner extends DirectoryScanner | |||
*/ | |||
protected static boolean match( String pattern, String str ) | |||
{ | |||
return DirectoryScanner.match( pattern, str ); | |||
return ScannerUtil.match( pattern, str ); | |||
} | |||
/** | |||
@@ -18,6 +18,7 @@ import com.starbase.util.Platform; | |||
import java.util.StringTokenizer; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.tools.ant.types.DirectoryScanner; | |||
import org.apache.tools.ant.types.ScannerUtil; | |||
/** | |||
* Checks out files from a specific StarTeam server, project, view, and folder. | |||
@@ -765,7 +766,7 @@ public class AntStarTeamCheckOut extends org.apache.tools.ant.Task | |||
StringTokenizer exStr = new StringTokenizer( patterns, " " ); | |||
while( exStr.hasMoreTokens() ) | |||
{ | |||
if( DirectoryScanner.match( exStr.nextToken(), pName ) ) | |||
if( ScannerUtil.match( exStr.nextToken(), pName ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -91,24 +91,6 @@ import org.apache.myrmidon.api.TaskException; | |||
public class DirectoryScanner | |||
implements FileScanner | |||
{ | |||
/** | |||
* Patterns that should be excluded by default. | |||
* | |||
* @see #addDefaultExcludes() | |||
*/ | |||
private final static String[] DEFAULTEXCLUDES = | |||
{ | |||
"**/*~", | |||
"**/#*#", | |||
"**/.#*", | |||
"**/%*%", | |||
"**/CVS", | |||
"**/CVS/**", | |||
"**/.cvsignore", | |||
"**/SCCS", | |||
"**/SCCS/**", | |||
"**/vssver.scc" | |||
}; | |||
/** | |||
* Have the ArrayLists holding our results been built by a slow scan? | |||
@@ -174,493 +156,6 @@ public class DirectoryScanner | |||
*/ | |||
private String[] m_includes; | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
public static boolean match( final String pattern, final String str ) | |||
{ | |||
return match( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @param isCaseSensitive Description of Parameter | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean match( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
char[] patArr = pattern.toCharArray(); | |||
char[] strArr = str.toCharArray(); | |||
int patIdxStart = 0; | |||
int patIdxEnd = patArr.length - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strArr.length - 1; | |||
char ch; | |||
boolean containsStar = false; | |||
for( int i = 0; i < patArr.length; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
containsStar = true; | |||
break; | |||
} | |||
} | |||
if( !containsStar ) | |||
{ | |||
// No '*'s, so we make a shortcut | |||
if( patIdxEnd != strIdxEnd ) | |||
{ | |||
return false;// Pattern and string do not have the same size | |||
} | |||
for( int i = 0; i <= patIdxEnd; i++ ) | |||
{ | |||
ch = patArr[ i ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ i ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ i ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
} | |||
return true;// String matches against pattern | |||
} | |||
if( patIdxEnd == 0 ) | |||
{ | |||
return true;// Pattern contains only '*', which matches anything | |||
} | |||
// Process characters before first star | |||
while( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// Process characters after last star | |||
while( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxEnd ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxEnd ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// process pattern between stars. padIdxStart and patIdxEnd point | |||
// always to a '*'. | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// Two stars next to each other, skip the first one. | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
ch = patArr[ patIdxStart + j + 1 ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart + i + j ] ) | |||
{ | |||
continue strLoop; | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart + i + j ] ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
// All characters in the string are used. Check if only '*'s are left | |||
// in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, final String str ) | |||
{ | |||
return matchPath( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must a case sensitive match be done? | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
} | |||
// up to last '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxEnd ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxEnd ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// '**/**' situation, so skip one | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
String subPat = (String)patDirs.get( patIdxStart + j + 1 ); | |||
String subStr = (String)strDirs.get( strIdxStart + i + j ); | |||
if( !match( subPat, subStr, isCaseSensitive ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, final String str ) | |||
{ | |||
return matchPatternStart( pattern, str, true ); | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must matches be case sensitive? | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
return true; | |||
} | |||
else if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
else | |||
{ | |||
// pattern now holds ** while string is not exhausted | |||
// this will generate false positives but we can live with that. | |||
return true; | |||
} | |||
} | |||
/** | |||
* Sets the basedir for scanning. This is the directory that is scanned | |||
* recursively. All '/' and '\' characters are replaced by <code>File.separatorChar</code> | |||
@@ -900,14 +395,14 @@ public class DirectoryScanner | |||
{ | |||
int excludesLength = m_excludes == null ? 0 : m_excludes.length; | |||
String[] newExcludes; | |||
newExcludes = new String[ excludesLength + DEFAULTEXCLUDES.length ]; | |||
newExcludes = new String[ excludesLength + ScannerUtil.DEFAULTEXCLUDES.length ]; | |||
if( excludesLength > 0 ) | |||
{ | |||
System.arraycopy( m_excludes, 0, newExcludes, 0, excludesLength ); | |||
} | |||
for( int i = 0; i < DEFAULTEXCLUDES.length; i++ ) | |||
for( int i = 0; i < ScannerUtil.DEFAULTEXCLUDES.length; i++ ) | |||
{ | |||
newExcludes[ i + excludesLength ] = DEFAULTEXCLUDES[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); | |||
newExcludes[ i + excludesLength ] = ScannerUtil.DEFAULTEXCLUDES[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ); | |||
} | |||
m_excludes = newExcludes; | |||
} | |||
@@ -982,7 +477,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_excludes.length; i++ ) | |||
{ | |||
if( matchPath( m_excludes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPath( m_excludes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1001,7 +496,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_includes.length; i++ ) | |||
{ | |||
if( matchPath( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPath( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1020,7 +515,7 @@ public class DirectoryScanner | |||
{ | |||
for( int i = 0; i < m_includes.length; i++ ) | |||
{ | |||
if( matchPatternStart( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
if( ScannerUtil.matchPatternStart( m_includes[ i ], name, m_isCaseSensitive ) ) | |||
{ | |||
return true; | |||
} | |||
@@ -1166,11 +661,6 @@ public class DirectoryScanner | |||
m_haveSlowResults = true; | |||
} | |||
public static String[] getDEFAULTEXCLUDES() | |||
{ | |||
return DEFAULTEXCLUDES; | |||
} | |||
public ArrayList getDirsExcluded() | |||
{ | |||
return m_dirsExcluded; | |||
@@ -13,23 +13,18 @@ import java.util.StringTokenizer; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.framework.Pattern; | |||
import org.apache.tools.ant.ProjectComponent; | |||
/** | |||
* Named collection of include/exclude tags. <p> | |||
* | |||
* Moved out of MatchingTask to make it a standalone object that could be | |||
* referenced (by scripts for example). | |||
* | |||
* @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a> | |||
* @author Stefano Mazzocchi <a href="mailto:stefano@apache.org"> | |||
* stefano@apache.org</a> | |||
* @author Sam Ruby <a href="mailto:rubys@us.ibm.com">rubys@us.ibm.com</a> | |||
* @author Jon S. Stevens <a href="mailto:jon@clearink.com">jon@clearink.com</a> | |||
* @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a> | |||
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> | |||
* @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> | |||
* @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a> | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
*/ | |||
public class PatternSet | |||
extends ProjectComponent | |||
{ | |||
private ArrayList m_includeList = new ArrayList(); | |||
private ArrayList m_excludeList = new ArrayList(); | |||
@@ -106,8 +101,8 @@ public class PatternSet | |||
public String toString() | |||
{ | |||
return "patternSet{ includes: " + m_includeList + | |||
" excludes: " + m_excludeList + " }"; | |||
return "PatternSet [ includes: " + m_includeList + | |||
" excludes: " + m_excludeList + " ]"; | |||
} | |||
private Pattern[] parsePatterns( final String patternString ) | |||
@@ -0,0 +1,525 @@ | |||
/* | |||
* Copyright (C) The Apache Software Foundation. All rights reserved. | |||
* | |||
* This software is published under the terms of the Apache Software License | |||
* version 1.1, a copy of which has been included with this distribution in | |||
* the LICENSE.txt file. | |||
*/ | |||
package org.apache.tools.ant.types; | |||
import java.io.File; | |||
import java.util.ArrayList; | |||
import java.util.StringTokenizer; | |||
/** | |||
* | |||
* | |||
* @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class ScannerUtil | |||
{ | |||
/** | |||
* Patterns that should be excluded by default. | |||
*/ | |||
public final static String[] DEFAULTEXCLUDES = new String[] | |||
{ | |||
"**/*~", | |||
"**/#*#", | |||
"**/.#*", | |||
"**/%*%", | |||
"**/CVS", | |||
"**/CVS/**", | |||
"**/.cvsignore", | |||
"**/SCCS", | |||
"**/SCCS/**", | |||
"**/vssver.scc" | |||
}; | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
public static boolean match( final String pattern, final String str ) | |||
{ | |||
return match( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a string against a pattern. The pattern contains two special | |||
* characters: '*' which means zero or more characters, '?' which means one | |||
* and only one character. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string that must be matched against the pattern | |||
* @param isCaseSensitive Description of Parameter | |||
* @return <code>true</code> when the string matches against the pattern, | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean match( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
char[] patArr = pattern.toCharArray(); | |||
char[] strArr = str.toCharArray(); | |||
int patIdxStart = 0; | |||
int patIdxEnd = patArr.length - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strArr.length - 1; | |||
char ch; | |||
boolean containsStar = false; | |||
for( int i = 0; i < patArr.length; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
containsStar = true; | |||
break; | |||
} | |||
} | |||
if( !containsStar ) | |||
{ | |||
// No '*'s, so we make a shortcut | |||
if( patIdxEnd != strIdxEnd ) | |||
{ | |||
return false;// Pattern and string do not have the same size | |||
} | |||
for( int i = 0; i <= patIdxEnd; i++ ) | |||
{ | |||
ch = patArr[ i ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ i ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ i ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
} | |||
return true;// String matches against pattern | |||
} | |||
if( patIdxEnd == 0 ) | |||
{ | |||
return true;// Pattern contains only '*', which matches anything | |||
} | |||
// Process characters before first star | |||
while( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// Process characters after last star | |||
while( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd ) | |||
{ | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxEnd ] ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxEnd ] ) ) | |||
{ | |||
return false;// Character mismatch | |||
} | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// All characters in the string are used. Check if only '*'s are | |||
// left in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
// process pattern between stars. padIdxStart and patIdxEnd point | |||
// always to a '*'. | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] == '*' ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// Two stars next to each other, skip the first one. | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
ch = patArr[ patIdxStart + j + 1 ]; | |||
if( ch != '?' ) | |||
{ | |||
if( isCaseSensitive && ch != strArr[ strIdxStart + i + j ] ) | |||
{ | |||
continue strLoop; | |||
} | |||
if( !isCaseSensitive && Character.toUpperCase( ch ) != | |||
Character.toUpperCase( strArr[ strIdxStart + i + j ] ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
// All characters in the string are used. Check if only '*'s are left | |||
// in the pattern. If so, we succeeded. Otherwise failure. | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patArr[ i ] != '*' ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, final String str ) | |||
{ | |||
return matchPath( pattern, str, true ); | |||
} | |||
/** | |||
* Matches a path against a pattern. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must a case sensitive match be done? | |||
* @return <code>true</code> when the pattern matches against the string. | |||
* <code>false</code> otherwise. | |||
*/ | |||
protected static boolean matchPath( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
else | |||
{ | |||
if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
} | |||
// up to last '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxEnd ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxEnd ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxEnd--; | |||
strIdxEnd--; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
int patIdxTmp = -1; | |||
for( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) | |||
{ | |||
if( patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
patIdxTmp = i; | |||
break; | |||
} | |||
} | |||
if( patIdxTmp == patIdxStart + 1 ) | |||
{ | |||
// '**/**' situation, so skip one | |||
patIdxStart++; | |||
continue; | |||
} | |||
// Find the pattern between padIdxStart & padIdxTmp in str between | |||
// strIdxStart & strIdxEnd | |||
int patLength = ( patIdxTmp - patIdxStart - 1 ); | |||
int strLength = ( strIdxEnd - strIdxStart + 1 ); | |||
int foundIdx = -1; | |||
strLoop : | |||
for( int i = 0; i <= strLength - patLength; i++ ) | |||
{ | |||
for( int j = 0; j < patLength; j++ ) | |||
{ | |||
String subPat = (String)patDirs.get( patIdxStart + j + 1 ); | |||
String subStr = (String)strDirs.get( strIdxStart + i + j ); | |||
if( !match( subPat, subStr, isCaseSensitive ) ) | |||
{ | |||
continue strLoop; | |||
} | |||
} | |||
foundIdx = strIdxStart + i; | |||
break; | |||
} | |||
if( foundIdx == -1 ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart = patIdxTmp; | |||
strIdxStart = foundIdx + patLength; | |||
} | |||
for( int i = patIdxStart; i <= patIdxEnd; i++ ) | |||
{ | |||
if( !patDirs.get( i ).equals( "**" ) ) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, final String str ) | |||
{ | |||
return matchPatternStart( pattern, str, true ); | |||
} | |||
/** | |||
* Does the path match the start of this pattern up to the first "**". <p> | |||
* | |||
* This is not a general purpose test and should only be used if you can | |||
* live with false positives.</p> <p> | |||
* | |||
* <code>pattern=**\\a</code> and <code>str=b</code> will yield true. | |||
* | |||
* @param pattern the (non-null) pattern to match against | |||
* @param str the (non-null) string (path) to match | |||
* @param isCaseSensitive must matches be case sensitive? | |||
* @return Description of the Returned Value | |||
*/ | |||
protected static boolean matchPatternStart( final String pattern, | |||
final String str, | |||
final boolean isCaseSensitive ) | |||
{ | |||
// When str starts with a File.separator, pattern has to start with a | |||
// File.separator. | |||
// When pattern starts with a File.separator, str has to start with a | |||
// File.separator. | |||
if( str.startsWith( File.separator ) != | |||
pattern.startsWith( File.separator ) ) | |||
{ | |||
return false; | |||
} | |||
ArrayList patDirs = new ArrayList(); | |||
StringTokenizer st = new StringTokenizer( pattern, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
patDirs.add( st.nextToken() ); | |||
} | |||
ArrayList strDirs = new ArrayList(); | |||
st = new StringTokenizer( str, File.separator ); | |||
while( st.hasMoreTokens() ) | |||
{ | |||
strDirs.add( st.nextToken() ); | |||
} | |||
int patIdxStart = 0; | |||
int patIdxEnd = patDirs.size() - 1; | |||
int strIdxStart = 0; | |||
int strIdxEnd = strDirs.size() - 1; | |||
// up to first '**' | |||
while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd ) | |||
{ | |||
String patDir = (String)patDirs.get( patIdxStart ); | |||
if( patDir.equals( "**" ) ) | |||
{ | |||
break; | |||
} | |||
if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) ) | |||
{ | |||
return false; | |||
} | |||
patIdxStart++; | |||
strIdxStart++; | |||
} | |||
if( strIdxStart > strIdxEnd ) | |||
{ | |||
// String is exhausted | |||
return true; | |||
} | |||
else if( patIdxStart > patIdxEnd ) | |||
{ | |||
// String not exhausted, but pattern is. Failure. | |||
return false; | |||
} | |||
else | |||
{ | |||
// pattern now holds ** while string is not exhausted | |||
// this will generate false positives but we can live with that. | |||
return true; | |||
} | |||
} | |||
} |