From fef5fd66d1100c2cea2d9573eeebfce6b03d6e04 Mon Sep 17 00:00:00 2001 From: Peter Donald Date: Thu, 24 Jan 2002 11:38:06 +0000 Subject: [PATCH] Create a utility class to contain all the static scanner utility functions git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@270840 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/tools/ant/taskdefs/Expand.java | 5 +- .../optional/ide/VAJWorkspaceScanner.java | 3 +- .../optional/scm/AntStarTeamCheckOut.java | 3 +- .../tools/ant/types/DirectoryScanner.java | 522 +---------------- .../apache/tools/ant/types/PatternSet.java | 19 +- .../apache/tools/ant/types/ScannerUtil.java | 525 ++++++++++++++++++ .../org/apache/tools/ant/taskdefs/Expand.java | 5 +- .../optional/ide/VAJWorkspaceScanner.java | 3 +- .../optional/scm/AntStarTeamCheckOut.java | 3 +- .../tools/ant/types/DirectoryScanner.java | 522 +---------------- .../apache/tools/ant/types/PatternSet.java | 19 +- .../apache/tools/ant/types/ScannerUtil.java | 525 ++++++++++++++++++ 12 files changed, 1090 insertions(+), 1064 deletions(-) create mode 100644 proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java create mode 100644 proposal/myrmidon/src/todo/org/apache/tools/ant/types/ScannerUtil.java diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/Expand.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/Expand.java index ffe124383..66a657e1a 100644 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/Expand.java +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/Expand.java @@ -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; diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java index d87c61245..d429e467e 100644 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java @@ -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 ); } /** diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java index 463bfb851..b16308621 100644 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java @@ -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; } diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/types/DirectoryScanner.java b/proposal/myrmidon/src/main/org/apache/tools/ant/types/DirectoryScanner.java index a8854b840..ac6496e5d 100644 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/types/DirectoryScanner.java +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/types/DirectoryScanner.java @@ -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 true when the string matches against the pattern, - * false 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 true when the string matches against the pattern, - * false 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 true when the pattern matches against the string. - * false 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 true when the pattern matches against the string. - * false 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 "**".

- * - * This is not a general purpose test and should only be used if you can - * live with false positives.

- * - * pattern=**\\a and str=b 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 "**".

- * - * This is not a general purpose test and should only be used if you can - * live with false positives.

- * - * pattern=**\\a and str=b 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 File.separatorChar @@ -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; diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/types/PatternSet.java b/proposal/myrmidon/src/main/org/apache/tools/ant/types/PatternSet.java index fa3e69850..ce86a5e7f 100644 --- a/proposal/myrmidon/src/main/org/apache/tools/ant/types/PatternSet.java +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/types/PatternSet.java @@ -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.

* - * Moved out of MatchingTask to make it a standalone object that could be - * referenced (by scripts for example). - * - * @author Arnout J. Kuiper ajkuiper@wxs.nl - * @author Stefano Mazzocchi - * stefano@apache.org - * @author Sam Ruby rubys@us.ibm.com - * @author Jon S. Stevens jon@clearink.com + * @author Arnout J. Kuiper + * @author Stefano Mazzocchi + * @author Sam Ruby + * @author Jon S. Stevens * @author Stefan Bodewig + * @author Peter Donald */ 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 ) diff --git a/proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java b/proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java new file mode 100644 index 000000000..7ade7091f --- /dev/null +++ b/proposal/myrmidon/src/main/org/apache/tools/ant/types/ScannerUtil.java @@ -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 Peter Donald + * @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 true when the string matches against the pattern, + * false 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 true when the string matches against the pattern, + * false 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 true when the pattern matches against the string. + * false 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 true when the pattern matches against the string. + * false 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 "**".

+ * + * This is not a general purpose test and should only be used if you can + * live with false positives.

+ * + * pattern=**\\a and str=b 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 "**".

+ * + * This is not a general purpose test and should only be used if you can + * live with false positives.

+ * + * pattern=**\\a and str=b 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; + } + } +} diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/Expand.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/Expand.java index ffe124383..66a657e1a 100644 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/Expand.java +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/Expand.java @@ -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; diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java index d87c61245..d429e467e 100644 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/ide/VAJWorkspaceScanner.java @@ -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 ); } /** diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java index 463bfb851..b16308621 100644 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/taskdefs/optional/scm/AntStarTeamCheckOut.java @@ -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; } diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/types/DirectoryScanner.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/DirectoryScanner.java index a8854b840..ac6496e5d 100644 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/types/DirectoryScanner.java +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/DirectoryScanner.java @@ -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 true when the string matches against the pattern, - * false 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 true when the string matches against the pattern, - * false 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 true when the pattern matches against the string. - * false 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 true when the pattern matches against the string. - * false 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 "**".

- * - * This is not a general purpose test and should only be used if you can - * live with false positives.

- * - * pattern=**\\a and str=b 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 "**".

- * - * This is not a general purpose test and should only be used if you can - * live with false positives.

- * - * pattern=**\\a and str=b 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 File.separatorChar @@ -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; diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/types/PatternSet.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/PatternSet.java index fa3e69850..ce86a5e7f 100644 --- a/proposal/myrmidon/src/todo/org/apache/tools/ant/types/PatternSet.java +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/PatternSet.java @@ -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.

* - * Moved out of MatchingTask to make it a standalone object that could be - * referenced (by scripts for example). - * - * @author Arnout J. Kuiper ajkuiper@wxs.nl - * @author Stefano Mazzocchi - * stefano@apache.org - * @author Sam Ruby rubys@us.ibm.com - * @author Jon S. Stevens jon@clearink.com + * @author Arnout J. Kuiper + * @author Stefano Mazzocchi + * @author Sam Ruby + * @author Jon S. Stevens * @author Stefan Bodewig + * @author Peter Donald */ 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 ) diff --git a/proposal/myrmidon/src/todo/org/apache/tools/ant/types/ScannerUtil.java b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/ScannerUtil.java new file mode 100644 index 000000000..7ade7091f --- /dev/null +++ b/proposal/myrmidon/src/todo/org/apache/tools/ant/types/ScannerUtil.java @@ -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 Peter Donald + * @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 true when the string matches against the pattern, + * false 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 true when the string matches against the pattern, + * false 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 true when the pattern matches against the string. + * false 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 true when the pattern matches against the string. + * false 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 "**".

+ * + * This is not a general purpose test and should only be used if you can + * live with false positives.

+ * + * pattern=**\\a and str=b 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 "**".

+ * + * This is not a general purpose test and should only be used if you can + * live with false positives.

+ * + * pattern=**\\a and str=b 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; + } + } +}