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.DirectoryScanner; | ||||
| import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
| import org.apache.tools.ant.types.PatternSet; | import org.apache.tools.ant.types.PatternSet; | ||||
| import org.apache.tools.ant.types.ScannerUtil; | |||||
| /** | /** | ||||
| * Unzip a file. | * Unzip a file. | ||||
| @@ -205,7 +206,7 @@ public class Expand extends MatchingTask | |||||
| { | { | ||||
| for( int w = 0; w < incls.length; w++ ) | for( int w = 0; w < incls.length; w++ ) | ||||
| { | { | ||||
| boolean isIncl = DirectoryScanner.match( incls[ w ], name ); | |||||
| boolean isIncl = ScannerUtil.match( incls[ w ], name ); | |||||
| if( isIncl ) | if( isIncl ) | ||||
| { | { | ||||
| included = true; | included = true; | ||||
| @@ -218,7 +219,7 @@ public class Expand extends MatchingTask | |||||
| { | { | ||||
| for( int w = 0; w < excls.length; w++ ) | for( int w = 0; w < excls.length; w++ ) | ||||
| { | { | ||||
| boolean isExcl = DirectoryScanner.match( excls[ w ], name ); | |||||
| boolean isExcl = ScannerUtil.match( excls[ w ], name ); | |||||
| if( isExcl ) | if( isExcl ) | ||||
| { | { | ||||
| included = false; | included = false; | ||||
| @@ -15,6 +15,7 @@ import java.util.ArrayList; | |||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
| import org.apache.tools.ant.types.DirectoryScanner; | 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 | * 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 ) | 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 java.util.StringTokenizer; | ||||
| import org.apache.myrmidon.api.TaskException; | import org.apache.myrmidon.api.TaskException; | ||||
| import org.apache.tools.ant.types.DirectoryScanner; | 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. | * 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, " " ); | StringTokenizer exStr = new StringTokenizer( patterns, " " ); | ||||
| while( exStr.hasMoreTokens() ) | while( exStr.hasMoreTokens() ) | ||||
| { | { | ||||
| if( DirectoryScanner.match( exStr.nextToken(), pName ) ) | |||||
| if( ScannerUtil.match( exStr.nextToken(), pName ) ) | |||||
| { | { | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -91,24 +91,6 @@ import org.apache.myrmidon.api.TaskException; | |||||
| public class DirectoryScanner | public class DirectoryScanner | ||||
| implements FileScanner | 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? | * Have the ArrayLists holding our results been built by a slow scan? | ||||
| @@ -174,493 +156,6 @@ public class DirectoryScanner | |||||
| */ | */ | ||||
| private String[] m_includes; | 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 | * Sets the basedir for scanning. This is the directory that is scanned | ||||
| * recursively. All '/' and '\' characters are replaced by <code>File.separatorChar</code> | * 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; | int excludesLength = m_excludes == null ? 0 : m_excludes.length; | ||||
| String[] newExcludes; | String[] newExcludes; | ||||
| newExcludes = new String[ excludesLength + DEFAULTEXCLUDES.length ]; | |||||
| newExcludes = new String[ excludesLength + ScannerUtil.DEFAULTEXCLUDES.length ]; | |||||
| if( excludesLength > 0 ) | if( excludesLength > 0 ) | ||||
| { | { | ||||
| System.arraycopy( m_excludes, 0, newExcludes, 0, excludesLength ); | 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; | m_excludes = newExcludes; | ||||
| } | } | ||||
| @@ -982,7 +477,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_excludes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1001,7 +496,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_includes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1020,7 +515,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_includes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1166,11 +661,6 @@ public class DirectoryScanner | |||||
| m_haveSlowResults = true; | m_haveSlowResults = true; | ||||
| } | } | ||||
| public static String[] getDEFAULTEXCLUDES() | |||||
| { | |||||
| return DEFAULTEXCLUDES; | |||||
| } | |||||
| public ArrayList getDirsExcluded() | public ArrayList getDirsExcluded() | ||||
| { | { | ||||
| return m_dirsExcluded; | return m_dirsExcluded; | ||||
| @@ -13,23 +13,18 @@ import java.util.StringTokenizer; | |||||
| import org.apache.myrmidon.api.TaskContext; | import org.apache.myrmidon.api.TaskContext; | ||||
| import org.apache.myrmidon.api.TaskException; | import org.apache.myrmidon.api.TaskException; | ||||
| import org.apache.myrmidon.framework.Pattern; | import org.apache.myrmidon.framework.Pattern; | ||||
| import org.apache.tools.ant.ProjectComponent; | |||||
| /** | /** | ||||
| * Named collection of include/exclude tags. <p> | * 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:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| */ | */ | ||||
| public class PatternSet | public class PatternSet | ||||
| extends ProjectComponent | |||||
| { | { | ||||
| private ArrayList m_includeList = new ArrayList(); | private ArrayList m_includeList = new ArrayList(); | ||||
| private ArrayList m_excludeList = new ArrayList(); | private ArrayList m_excludeList = new ArrayList(); | ||||
| @@ -106,8 +101,8 @@ public class PatternSet | |||||
| public String toString() | 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 ) | 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.DirectoryScanner; | ||||
| import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
| import org.apache.tools.ant.types.PatternSet; | import org.apache.tools.ant.types.PatternSet; | ||||
| import org.apache.tools.ant.types.ScannerUtil; | |||||
| /** | /** | ||||
| * Unzip a file. | * Unzip a file. | ||||
| @@ -205,7 +206,7 @@ public class Expand extends MatchingTask | |||||
| { | { | ||||
| for( int w = 0; w < incls.length; w++ ) | for( int w = 0; w < incls.length; w++ ) | ||||
| { | { | ||||
| boolean isIncl = DirectoryScanner.match( incls[ w ], name ); | |||||
| boolean isIncl = ScannerUtil.match( incls[ w ], name ); | |||||
| if( isIncl ) | if( isIncl ) | ||||
| { | { | ||||
| included = true; | included = true; | ||||
| @@ -218,7 +219,7 @@ public class Expand extends MatchingTask | |||||
| { | { | ||||
| for( int w = 0; w < excls.length; w++ ) | for( int w = 0; w < excls.length; w++ ) | ||||
| { | { | ||||
| boolean isExcl = DirectoryScanner.match( excls[ w ], name ); | |||||
| boolean isExcl = ScannerUtil.match( excls[ w ], name ); | |||||
| if( isExcl ) | if( isExcl ) | ||||
| { | { | ||||
| included = false; | included = false; | ||||
| @@ -15,6 +15,7 @@ import java.util.ArrayList; | |||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
| import org.apache.tools.ant.types.DirectoryScanner; | 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 | * 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 ) | 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 java.util.StringTokenizer; | ||||
| import org.apache.myrmidon.api.TaskException; | import org.apache.myrmidon.api.TaskException; | ||||
| import org.apache.tools.ant.types.DirectoryScanner; | 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. | * 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, " " ); | StringTokenizer exStr = new StringTokenizer( patterns, " " ); | ||||
| while( exStr.hasMoreTokens() ) | while( exStr.hasMoreTokens() ) | ||||
| { | { | ||||
| if( DirectoryScanner.match( exStr.nextToken(), pName ) ) | |||||
| if( ScannerUtil.match( exStr.nextToken(), pName ) ) | |||||
| { | { | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -91,24 +91,6 @@ import org.apache.myrmidon.api.TaskException; | |||||
| public class DirectoryScanner | public class DirectoryScanner | ||||
| implements FileScanner | 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? | * Have the ArrayLists holding our results been built by a slow scan? | ||||
| @@ -174,493 +156,6 @@ public class DirectoryScanner | |||||
| */ | */ | ||||
| private String[] m_includes; | 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 | * Sets the basedir for scanning. This is the directory that is scanned | ||||
| * recursively. All '/' and '\' characters are replaced by <code>File.separatorChar</code> | * 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; | int excludesLength = m_excludes == null ? 0 : m_excludes.length; | ||||
| String[] newExcludes; | String[] newExcludes; | ||||
| newExcludes = new String[ excludesLength + DEFAULTEXCLUDES.length ]; | |||||
| newExcludes = new String[ excludesLength + ScannerUtil.DEFAULTEXCLUDES.length ]; | |||||
| if( excludesLength > 0 ) | if( excludesLength > 0 ) | ||||
| { | { | ||||
| System.arraycopy( m_excludes, 0, newExcludes, 0, excludesLength ); | 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; | m_excludes = newExcludes; | ||||
| } | } | ||||
| @@ -982,7 +477,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_excludes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1001,7 +496,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_includes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1020,7 +515,7 @@ public class DirectoryScanner | |||||
| { | { | ||||
| for( int i = 0; i < m_includes.length; i++ ) | 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; | return true; | ||||
| } | } | ||||
| @@ -1166,11 +661,6 @@ public class DirectoryScanner | |||||
| m_haveSlowResults = true; | m_haveSlowResults = true; | ||||
| } | } | ||||
| public static String[] getDEFAULTEXCLUDES() | |||||
| { | |||||
| return DEFAULTEXCLUDES; | |||||
| } | |||||
| public ArrayList getDirsExcluded() | public ArrayList getDirsExcluded() | ||||
| { | { | ||||
| return m_dirsExcluded; | return m_dirsExcluded; | ||||
| @@ -13,23 +13,18 @@ import java.util.StringTokenizer; | |||||
| import org.apache.myrmidon.api.TaskContext; | import org.apache.myrmidon.api.TaskContext; | ||||
| import org.apache.myrmidon.api.TaskException; | import org.apache.myrmidon.api.TaskException; | ||||
| import org.apache.myrmidon.framework.Pattern; | import org.apache.myrmidon.framework.Pattern; | ||||
| import org.apache.tools.ant.ProjectComponent; | |||||
| /** | /** | ||||
| * Named collection of include/exclude tags. <p> | * 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:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| */ | */ | ||||
| public class PatternSet | public class PatternSet | ||||
| extends ProjectComponent | |||||
| { | { | ||||
| private ArrayList m_includeList = new ArrayList(); | private ArrayList m_includeList = new ArrayList(); | ||||
| private ArrayList m_excludeList = new ArrayList(); | private ArrayList m_excludeList = new ArrayList(); | ||||
| @@ -106,8 +101,8 @@ public class PatternSet | |||||
| public String toString() | 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 ) | 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; | |||||
| } | |||||
| } | |||||
| } | |||||