1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-08-09 17:25:38 +02:00
This commit is contained in:
David Inglis 2004-03-26 17:33:44 +00:00
parent 69b06bd290
commit 1bf2a95bf6
5 changed files with 467 additions and 502 deletions

View file

@ -1,3 +1,13 @@
2004-03-26 David Inglis
Refactor to move exclusion matching methods out into public class.
* model/org/eclipse/cdt/core/model/CoreModelUtil.java
* model/org/eclipse/cdt/internal/core/model/CProject.java
* model/org/eclipse/cdt/internal/core/model/SourceRoot.java
* model/org/eclipse/cdt/internal/core/model/Util.java
2004-03-25 David Inglis
Added util class for core model

View file

@ -1,6 +1,6 @@
package org.eclipse.cdt.core.model;
import org.eclipse.cdt.internal.core.CharOperation;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IPath;
public class CoreModelUtil {
@ -9,7 +9,7 @@ public class CoreModelUtil {
char[] path = resourcePath.toString().toCharArray();
for (int i = 0, length = exclusionPatterns.length; i < length; i++) {
char[] pattern = exclusionPatterns[i].toString().toCharArray();
if (CharOperation.pathMatch(pattern, path, true, '/')) {
if (pathMatch(pattern, path, true, '/')) {
return true;
}
}
@ -17,19 +17,465 @@ public class CoreModelUtil {
}
/*
* Returns whether the given resource path matches one of the exclusion
* patterns.
* Returns whether the given resource path matches one of the exclusion patterns.
*
* @see IPathEntry#getExclusionPatterns
* @see IClasspathEntry#getExclusionPatterns
*/
public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
if (exclusionPatterns == null)
return false;
char[] path = resourcePath.toString().toCharArray();
for (int i = 0, length = exclusionPatterns.length; i < length; i++)
if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
if (pathMatch(exclusionPatterns[i], path, true, '/'))
return true;
return false;
}
/*
* Returns whether the given resource matches one of the exclusion patterns.
*
* @see IClasspathEntry#getExclusionPatterns
*/
public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
IPath path = resource.getFullPath();
// ensure that folders are only excluded if all of their children are
// excluded
if (resource.getType() == IResource.FOLDER)
path = path.append("*"); //$NON-NLS-1$
return isExcluded(path, exclusionPatterns);
}
/**
* Answers true if the pattern matches the given name, false otherwise. This char[] pattern matching accepts wild-cards '*' and
* '?'.
*
* When not case sensitive, the pattern is assumed to already be lowercased, the name will be lowercased character per character
* as comparing. If name is null, the answer is false. If pattern is null, the answer is true if name is not null. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
*
* pattern = { '?', 'b', '*' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; true
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* pattern = { '?', 'b', '?' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; false
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* pattern = { 'b', '*' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; false
*
* </pre>
*
* </li>
* </ol>
*
* @param pattern
* the given pattern
* @param name
* the given name
* @param isCaseSensitive
* flag to know whether or not the matching should be case sensitive
* @return true if the pattern matches the given name, false otherwise
*/
public static final boolean match(char[] pattern, char[] name, boolean isCaseSensitive) {
if (name == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
return match(pattern, 0, pattern.length, name, 0, name.length, isCaseSensitive);
}
/**
* Answers true if the a sub-pattern matches the subpart of the given name, false otherwise. char[] pattern matching, accepting
* wild-cards '*' and '?'. Can match only subset of name/pattern. end positions are non-inclusive. The subpattern is defined by
* the patternStart and pattternEnd positions. When not case sensitive, the pattern is assumed to already be lowercased, the
* name will be lowercased character per character as comparing. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
*
* pattern = { '?', 'b', '*' }
* patternStart = 1
* patternEnd = 3
* name = { 'a', 'b', 'c' , 'd' }
* nameStart = 1
* nameEnd = 4
* isCaseSensitive = true
* result =&gt; true
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* pattern = { '?', 'b', '*' }
* patternStart = 1
* patternEnd = 2
* name = { 'a', 'b', 'c' , 'd' }
* nameStart = 1
* nameEnd = 2
* isCaseSensitive = true
* result =&gt; false
*
* </pre>
*
* </li>
* </ol>
*
* @param pattern
* the given pattern
* @param patternStart
* the given pattern start
* @param patternEnd
* the given pattern end
* @param name
* the given name
* @param nameStart
* the given name start
* @param nameEnd
* the given name end
* @param isCaseSensitive
* flag to know if the matching should be case sensitive
* @return true if the a sub-pattern matches the subpart of the given name, false otherwise
*/
public static final boolean match(char[] pattern, int patternStart, int patternEnd, char[] name, int nameStart, int nameEnd,
boolean isCaseSensitive) {
if (name == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
int iPattern = patternStart;
int iName = nameStart;
if (patternEnd < 0)
patternEnd = pattern.length;
if (nameEnd < 0)
nameEnd = name.length;
/* check first segment */
char patternChar = 0;
while ((iPattern < patternEnd) && (patternChar = pattern[iPattern]) != '*') {
if (iName == nameEnd)
return false;
if (patternChar != (isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) && patternChar != '?') {
return false;
}
iName++;
iPattern++;
}
/* check sequence of star+segment */
int segmentStart;
if (patternChar == '*') {
segmentStart = ++iPattern; // skip star
} else {
segmentStart = 0; // force iName check
}
int prefixStart = iName;
checkSegment : while (iName < nameEnd) {
if (iPattern == patternEnd) {
iPattern = segmentStart; // mismatch - restart current segment
iName = ++prefixStart;
continue checkSegment;
}
/* segment is ending */
if ((patternChar = pattern[iPattern]) == '*') {
segmentStart = ++iPattern; // skip start
if (segmentStart == patternEnd) {
return true;
}
prefixStart = iName;
continue checkSegment;
}
/* check current name character */
if ((isCaseSensitive ? name[iName] : Character.toLowerCase(name[iName])) != patternChar && patternChar != '?') {
iPattern = segmentStart; // mismatch - restart current segment
iName = ++prefixStart;
continue checkSegment;
}
iName++;
iPattern++;
}
return (segmentStart == patternEnd) || (iName == nameEnd && iPattern == patternEnd)
|| (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
}
/**
* Answers true if the pattern matches the filepath using the pathSepatator, false otherwise.
*
* Path char[] pattern matching, accepting wild-cards '**', '*' and '?' (using Ant directory tasks conventions, also see
* "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes"). Path pattern matching is enhancing regular pattern
* matching in supporting extra rule where '**' represent any folder combination. Special rule: - foo\ is equivalent to foo\**
* When not case sensitive, the pattern is assumed to already be lowercased, the name will be lowercased character per character
* as comparing.
*
* @param pattern
* the given pattern
* @param filepath
* the given path
* @param isCaseSensitive
* to find out whether or not the matching should be case sensitive
* @param pathSeparator
* the given path separator
* @return true if the pattern matches the filepath using the pathSepatator, false otherwise
*/
public static final boolean pathMatch(char[] pattern, char[] filepath, boolean isCaseSensitive, char pathSeparator) {
if (filepath == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
// offsets inside pattern
int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0;
int pLength = pattern.length;
int pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart + 1);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
// special case: pattern foo\ is equivalent to foo\**
boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
// offsets inside filepath
int fSegmentStart, fLength = filepath.length;
if (filepath[0] != pathSeparator) {
fSegmentStart = 0;
} else {
fSegmentStart = 1;
}
if (fSegmentStart != pSegmentStart) {
return false; // both must start with a separator or none.
}
int fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart + 1);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
// first segments
while (pSegmentStart < pLength
&& !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2
&& pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) {
if (fSegmentStart >= fLength)
return false;
if (!match(pattern, pSegmentStart, pSegmentEnd, filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
return false;
}
// jump to next segment
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart = fSegmentEnd + 1);
// skip separator
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
}
/* check sequence of doubleStar+segment */
int pSegmentRestart;
if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
|| (pSegmentEnd == pSegmentStart + 2 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) {
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
pSegmentRestart = pSegmentStart;
} else {
if (pSegmentStart >= pLength)
return fSegmentStart >= fLength; // true if filepath is done
// too.
pSegmentRestart = 0; // force fSegmentStart check
}
int fSegmentRestart = fSegmentStart;
checkSegment : while (fSegmentStart < fLength) {
if (pSegmentStart >= pLength) {
if (freeTrailingDoubleStar)
return true;
// mismatch - restart current path segment
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentRestart = indexOf(pathSeparator, filepath, fSegmentRestart + 1);
// skip separator
if (fSegmentRestart < 0) {
fSegmentRestart = fLength;
} else {
fSegmentRestart++;
}
fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
continue checkSegment;
}
/* path segment is ending */
if (pSegmentEnd == pSegmentStart + 2 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*') {
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
pSegmentRestart = pSegmentStart;
fSegmentRestart = fSegmentStart;
if (pSegmentStart >= pLength)
return true;
continue checkSegment;
}
/* chech current path segment */
if (!match(pattern, pSegmentStart, pSegmentEnd, filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
// mismatch - restart current path segment
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentRestart);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentRestart = indexOf(pathSeparator, filepath, fSegmentRestart + 1);
// skip separator
if (fSegmentRestart < 0) {
fSegmentRestart = fLength;
} else {
fSegmentRestart++;
}
fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart = fSegmentRestart);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
continue checkSegment;
}
// jump to next segment
pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart = fSegmentEnd + 1);
// skip separator
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
}
return (pSegmentRestart >= pSegmentEnd) || (fSegmentStart >= fLength && pSegmentStart >= pLength)
|| (pSegmentStart == pLength - 2 && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')
|| (pSegmentStart == pLength && freeTrailingDoubleStar);
}
/**
* Answers the first index in the array for which the corresponding character is equal to toBeFound. Answers -1 if no occurrence
* of this character is found. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
*
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* result =&gt; 2
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* toBeFound = 'e'
* array = { ' a', 'b', 'c', 'd' }
* result =&gt; -1
*
* </pre>
*
* </li>
* </ol>
*
* @param toBeFound
* the character to search
* @param array
* the array to be searched
* @return the first index in the array for which the corresponding character is equal to toBeFound, -1 otherwise
* @throws NullPointerException
* if array is null
*/
public static final int indexOf(char toBeFound, char[] array) {
for (int i = 0; i < array.length; i++)
if (toBeFound == array[i])
return i;
return -1;
}
/**
* Answers the first index in the array for which the corresponding character is equal to toBeFound starting the search at index
* start. Answers -1 if no occurrence of this character is found. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
*
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* start = 2
* result =&gt; 2
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* start = 3
* result =&gt; -1
*
* </pre>
*
* </li>
* <li>
*
* <pre>
*
* toBeFound = 'e'
* array = { ' a', 'b', 'c', 'd' }
* start = 1
* result =&gt; -1
*
* </pre>
*
* </li>
* </ol>
*
* @param toBeFound
* the character to search
* @param array
* the array to be searched
* @param start
* the starting index
* @return the first index in the array for which the corresponding character is equal to toBeFound, -1 otherwise
* @throws NullPointerException
* if array is null
* @throws ArrayIndexOutOfBoundsException
* if start is lower than 0
*/
public static final int indexOf(char toBeFound, char[] array, int start) {
for (int i = start; i < array.length; i++)
if (toBeFound == array[i])
return i;
return -1;
}
}

View file

@ -21,6 +21,7 @@ import org.eclipse.cdt.core.IBinaryParser.IBinaryFile;
import org.eclipse.cdt.core.IBinaryParser.IBinaryObject;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.IArchiveContainer;
import org.eclipse.cdt.core.model.IBinaryContainer;
import org.eclipse.cdt.core.model.ICElement;
@ -462,7 +463,7 @@ public class CProject extends Openable implements ICProject {
}
private boolean isOnOutputEntry(IOutputEntry entry, IPath path) {
if (entry.getPath().isPrefixOf(path) && !Util.isExcluded(path, entry.fullExclusionPatternChars())) {
if (entry.getPath().isPrefixOf(path) && !CoreModelUtil.isExcluded(path, entry.fullExclusionPatternChars())) {
return true;
}
return false;

View file

@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.model;
import java.util.ArrayList;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ISourceEntry;
@ -118,7 +119,7 @@ public class SourceRoot extends CContainer implements ISourceRoot {
private boolean isOnSourceEntry(IPath path) {
if (sourceEntry.getPath().isPrefixOf(path)
&& !Util.isExcluded(path, sourceEntry.fullExclusionPatternChars())) {
&& !CoreModelUtil.isExcluded(path, sourceEntry.fullExclusionPatternChars())) {
return true;
}
return false;

View file

@ -9,15 +9,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ICLogConstants;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.ICModelStatusConstants;
import org.eclipse.cdt.internal.core.model.IDebugLogConstants.DebugLogConstant;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@ -286,496 +285,4 @@ public class Util implements ICLogConstants {
}
return a.equals(b);
}
/*
* Returns whether the given resource path matches one of the exclusion
* patterns.
*
* @see IClasspathEntry#getExclusionPatterns
*/
public final static boolean isExcluded(IPath resourcePath,
char[][] exclusionPatterns) {
if (exclusionPatterns == null)
return false;
char[] path = resourcePath.toString().toCharArray();
for (int i = 0, length = exclusionPatterns.length; i < length; i++)
if (pathMatch(exclusionPatterns[i], path, true, '/'))
return true;
return false;
}
/*
* Returns whether the given resource matches one of the exclusion
* patterns.
*
* @see IClasspathEntry#getExclusionPatterns
*/
public final static boolean isExcluded(IResource resource,
char[][] exclusionPatterns) {
IPath path = resource.getFullPath();
// ensure that folders are only excluded if all of their children are
// excluded
if (resource.getType() == IResource.FOLDER)
path = path.append("*"); //$NON-NLS-1$
return isExcluded(path, exclusionPatterns);
}
/**
* Answers true if the pattern matches the given name, false otherwise.
* This char[] pattern matching accepts wild-cards '*' and '?'.
*
* When not case sensitive, the pattern is assumed to already be
* lowercased, the name will be lowercased character per character as
* comparing. If name is null, the answer is false. If pattern is null, the
* answer is true if name is not null. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
* pattern = { '?', 'b', '*' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; true
* </pre>
*
* </li>
* <li>
*
* <pre>
* pattern = { '?', 'b', '?' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; false
* </pre>
*
* </li>
* <li>
*
* <pre>
* pattern = { 'b', '*' }
* name = { 'a', 'b', 'c' , 'd' }
* isCaseSensitive = true
* result =&gt; false
* </pre>
*
* </li>
* </ol>
*
* @param pattern
* the given pattern
* @param name
* the given name
* @param isCaseSensitive
* flag to know whether or not the matching should be case
* sensitive
* @return true if the pattern matches the given name, false otherwise
*/
public static final boolean match(char[] pattern, char[] name,
boolean isCaseSensitive) {
if (name == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
return match(pattern, 0, pattern.length, name, 0, name.length,
isCaseSensitive);
}
/**
* Answers true if the a sub-pattern matches the subpart of the given name,
* false otherwise. char[] pattern matching, accepting wild-cards '*' and
* '?'. Can match only subset of name/pattern. end positions are
* non-inclusive. The subpattern is defined by the patternStart and
* pattternEnd positions. When not case sensitive, the pattern is assumed
* to already be lowercased, the name will be lowercased character per
* character as comparing. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
* pattern = { '?', 'b', '*' }
* patternStart = 1
* patternEnd = 3
* name = { 'a', 'b', 'c' , 'd' }
* nameStart = 1
* nameEnd = 4
* isCaseSensitive = true
* result =&gt; true
* </pre>
*
* </li>
* <li>
*
* <pre>
* pattern = { '?', 'b', '*' }
* patternStart = 1
* patternEnd = 2
* name = { 'a', 'b', 'c' , 'd' }
* nameStart = 1
* nameEnd = 2
* isCaseSensitive = true
* result =&gt; false
* </pre>
*
* </li>
* </ol>
*
* @param pattern
* the given pattern
* @param patternStart
* the given pattern start
* @param patternEnd
* the given pattern end
* @param name
* the given name
* @param nameStart
* the given name start
* @param nameEnd
* the given name end
* @param isCaseSensitive
* flag to know if the matching should be case sensitive
* @return true if the a sub-pattern matches the subpart of the given name,
* false otherwise
*/
public static final boolean match(char[] pattern, int patternStart,
int patternEnd, char[] name, int nameStart, int nameEnd,
boolean isCaseSensitive) {
if (name == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
int iPattern = patternStart;
int iName = nameStart;
if (patternEnd < 0)
patternEnd = pattern.length;
if (nameEnd < 0)
nameEnd = name.length;
/* check first segment */
char patternChar = 0;
while ((iPattern < patternEnd)
&& (patternChar = pattern[iPattern]) != '*') {
if (iName == nameEnd)
return false;
if (patternChar != (isCaseSensitive ? name[iName] : Character
.toLowerCase(name[iName]))
&& patternChar != '?') {
return false;
}
iName++;
iPattern++;
}
/* check sequence of star+segment */
int segmentStart;
if (patternChar == '*') {
segmentStart = ++iPattern; // skip star
} else {
segmentStart = 0; // force iName check
}
int prefixStart = iName;
checkSegment : while (iName < nameEnd) {
if (iPattern == patternEnd) {
iPattern = segmentStart; // mismatch - restart current segment
iName = ++prefixStart;
continue checkSegment;
}
/* segment is ending */
if ((patternChar = pattern[iPattern]) == '*') {
segmentStart = ++iPattern; // skip start
if (segmentStart == patternEnd) {
return true;
}
prefixStart = iName;
continue checkSegment;
}
/* check current name character */
if ((isCaseSensitive ? name[iName] : Character
.toLowerCase(name[iName])) != patternChar
&& patternChar != '?') {
iPattern = segmentStart; // mismatch - restart current segment
iName = ++prefixStart;
continue checkSegment;
}
iName++;
iPattern++;
}
return (segmentStart == patternEnd)
|| (iName == nameEnd && iPattern == patternEnd)
|| (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
}
/**
* Answers true if the pattern matches the filepath using the
* pathSepatator, false otherwise.
*
* Path char[] pattern matching, accepting wild-cards '**', '*' and '?'
* (using Ant directory tasks conventions, also see
* "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes").
* Path pattern matching is enhancing regular pattern matching in
* supporting extra rule where '**' represent any folder combination.
* Special rule: - foo\ is equivalent to foo\** When not case sensitive,
* the pattern is assumed to already be lowercased, the name will be
* lowercased character per character as comparing.
*
* @param pattern
* the given pattern
* @param filepath
* the given path
* @param isCaseSensitive
* to find out whether or not the matching should be case
* sensitive
* @param pathSeparator
* the given path separator
* @return true if the pattern matches the filepath using the
* pathSepatator, false otherwise
*/
public static final boolean pathMatch(char[] pattern, char[] filepath,
boolean isCaseSensitive, char pathSeparator) {
if (filepath == null)
return false; // null name cannot match
if (pattern == null)
return true; // null pattern is equivalent to '*'
// offsets inside pattern
int pSegmentStart = pattern[0] == pathSeparator ? 1 : 0;
int pLength = pattern.length;
int pSegmentEnd = indexOf(pathSeparator, pattern, pSegmentStart + 1);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
// special case: pattern foo\ is equivalent to foo\**
boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
// offsets inside filepath
int fSegmentStart, fLength = filepath.length;
if (filepath[0] != pathSeparator) {
fSegmentStart = 0;
} else {
fSegmentStart = 1;
}
if (fSegmentStart != pSegmentStart) {
return false; // both must start with a separator or none.
}
int fSegmentEnd = indexOf(pathSeparator, filepath, fSegmentStart + 1);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
// first segments
while (pSegmentStart < pLength
&& !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2
&& pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) {
if (fSegmentStart >= fLength)
return false;
if (!match(pattern, pSegmentStart, pSegmentEnd, filepath,
fSegmentStart, fSegmentEnd, isCaseSensitive)) {
return false;
}
// jump to next segment
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentEnd = indexOf(pathSeparator, filepath,
fSegmentStart = fSegmentEnd + 1);
// skip separator
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
}
/* check sequence of doubleStar+segment */
int pSegmentRestart;
if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
|| (pSegmentEnd == pSegmentStart + 2
&& pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) {
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
pSegmentRestart = pSegmentStart;
} else {
if (pSegmentStart >= pLength)
return fSegmentStart >= fLength; // true if filepath is done
// too.
pSegmentRestart = 0; // force fSegmentStart check
}
int fSegmentRestart = fSegmentStart;
checkSegment : while (fSegmentStart < fLength) {
if (pSegmentStart >= pLength) {
if (freeTrailingDoubleStar)
return true;
// mismatch - restart current path segment
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentRestart);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentRestart = indexOf(pathSeparator, filepath,
fSegmentRestart + 1);
// skip separator
if (fSegmentRestart < 0) {
fSegmentRestart = fLength;
} else {
fSegmentRestart++;
}
fSegmentEnd = indexOf(pathSeparator, filepath,
fSegmentStart = fSegmentRestart);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
continue checkSegment;
}
/* path segment is ending */
if (pSegmentEnd == pSegmentStart + 2
&& pattern[pSegmentStart] == '*'
&& pattern[pSegmentStart + 1] == '*') {
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
pSegmentRestart = pSegmentStart;
fSegmentRestart = fSegmentStart;
if (pSegmentStart >= pLength)
return true;
continue checkSegment;
}
/* chech current path segment */
if (!match(pattern, pSegmentStart, pSegmentEnd, filepath,
fSegmentStart, fSegmentEnd, isCaseSensitive)) {
// mismatch - restart current path segment
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentRestart);
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentRestart = indexOf(pathSeparator, filepath,
fSegmentRestart + 1);
// skip separator
if (fSegmentRestart < 0) {
fSegmentRestart = fLength;
} else {
fSegmentRestart++;
}
fSegmentEnd = indexOf(pathSeparator, filepath,
fSegmentStart = fSegmentRestart);
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
continue checkSegment;
}
// jump to next segment
pSegmentEnd = indexOf(pathSeparator, pattern,
pSegmentStart = pSegmentEnd + 1);
// skip separator
if (pSegmentEnd < 0)
pSegmentEnd = pLength;
fSegmentEnd = indexOf(pathSeparator, filepath,
fSegmentStart = fSegmentEnd + 1);
// skip separator
if (fSegmentEnd < 0)
fSegmentEnd = fLength;
}
return (pSegmentRestart >= pSegmentEnd)
|| (fSegmentStart >= fLength && pSegmentStart >= pLength)
|| (pSegmentStart == pLength - 2
&& pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')
|| (pSegmentStart == pLength && freeTrailingDoubleStar);
}
/**
* Answers the first index in the array for which the corresponding
* character is equal to toBeFound. Answers -1 if no occurrence of this
* character is found. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* result =&gt; 2
* </pre>
*
* </li>
* <li>
*
* <pre>
* toBeFound = 'e'
* array = { ' a', 'b', 'c', 'd' }
* result =&gt; -1
* </pre>
*
* </li>
* </ol>
*
* @param toBeFound
* the character to search
* @param array
* the array to be searched
* @return the first index in the array for which the corresponding
* character is equal to toBeFound, -1 otherwise
* @throws NullPointerException
* if array is null
*/
public static final int indexOf(char toBeFound, char[] array) {
for (int i = 0; i < array.length; i++)
if (toBeFound == array[i])
return i;
return -1;
}
/**
* Answers the first index in the array for which the corresponding
* character is equal to toBeFound starting the search at index start.
* Answers -1 if no occurrence of this character is found. <br>
* <br>
* For example:
* <ol>
* <li>
*
* <pre>
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* start = 2
* result =&gt; 2
* </pre>
*
* </li>
* <li>
*
* <pre>
* toBeFound = 'c'
* array = { ' a', 'b', 'c', 'd' }
* start = 3
* result =&gt; -1
* </pre>
*
* </li>
* <li>
*
* <pre>
* toBeFound = 'e'
* array = { ' a', 'b', 'c', 'd' }
* start = 1
* result =&gt; -1
* </pre>
*
* </li>
* </ol>
*
* @param toBeFound
* the character to search
* @param array
* the array to be searched
* @param start
* the starting index
* @return the first index in the array for which the corresponding
* character is equal to toBeFound, -1 otherwise
* @throws NullPointerException
* if array is null
* @throws ArrayIndexOutOfBoundsException
* if start is lower than 0
*/
public static final int indexOf(char toBeFound, char[] array, int start) {
for (int i = start; i < array.length; i++)
if (toBeFound == array[i])
return i;
return -1;
}
}