tbennett    2004/04/19 11:12:12

  Added:       composition/impl/src/java/org/apache/avalon/composition/util
                        FileUtils.java Resource.java ScannerUtils.java
  Log:
  Support/helpers for the FilesetModel/DirectoryScanner
  
  Revision  Changes    Path
  1.1                  
avalon/composition/impl/src/java/org/apache/avalon/composition/util/FileUtils.java
  
  Index: FileUtils.java
  ===================================================================
  /*
   * Copyright  2000-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.avalon.composition.util;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.Stack;
  import java.util.StringTokenizer;
  
  import org.apache.avalon.util.env.Env;
  
  /**
   * This class provides some common file utilities used by the
   * composition implementation, and is borrowed from the Apache
   * Ant development team.
   *
   * @author Apache Ant Development Team (MacNeill, Umasankar, and Bodewig)
   * @author <a href="mailto:[EMAIL PROTECTED]">Avalon Development Team</a>
   * @version $Revision: 1.1 $ $Date: 2004/04/19 18:12:12 $
   */
  public class FileUtils {
  
      private boolean onNetWare = Env.isNetWare();
      
      /**
       * Factory method.
       *
       * @return a new instance of FileUtils.
       */
      public static FileUtils newFileUtils() {
          return new FileUtils();
      }
  
      /**
       * Empty constructor.
       */
      protected FileUtils() {
      }
  
      /**
       * Checks whether a given file is a symbolic link.
       *
       * <p>It doesn't really test for symbolic links but whether the
       * canonical and absolute paths of the file are identical - this
       * may lead to false positives on some platforms.</p>
       *
       * @param parent the parent directory of the file to test
       * @param name the name of the file to test.
       * @return true if the file is a symbolic link.
       */
      public boolean isSymbolicLink(File parent, String name)
          throws IOException
      {
          File resolvedParent = new File( parent.getCanonicalPath() );
          File toTest = new File( resolvedParent, name );
          return !toTest.getAbsolutePath().equals( toTest.getCanonicalPath() );
      }
  
      /**
       * Removes a leading path from a second path.
       *
       * @param leading The leading path, must not be null, must be absolute.
       * @param path The path to remove from, must not be null, must be absolute.
       *
       * @return path's normalized absolute if it doesn't start with
       * leading, path's path with leading's path removed otherwise.
       */
      public String removeLeadingPath(File leading, File path) throws IOException {
          String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
          String p = normalize(path.getAbsolutePath()).getAbsolutePath();
          if (l.equals(p)) {
              return "";
          }
  
          // ensure that l ends with a /
          // so we never think /foo was a parent directory of /foobar
          if (!l.endsWith(File.separator)) {
              l += File.separator;
          }
  
          if (p.startsWith(l)) {
              return p.substring(l.length());
          } else {
              return p;
          }
      }
  
      /**
       * &quot;normalize&quot; the given absolute path.
       *
       * <p>This includes:
       * <ul>
       *   <li>Uppercase the drive letter if there is one.</li>
       *   <li>Remove redundant slashes after the drive spec.</li>
       *   <li>resolve all ./, .\, ../ and ..\ sequences.</li>
       *   <li>DOS style paths that start with a drive letter will have
       *     \ as the separator.</li>
       * </ul>
       * Unlike <code>File#getCanonicalPath()</code> it specifically doesn't
       * resolve symbolic links.
       *
       * @param path the path to be normalized
       * @return the normalized version of the path.
       *
       * @throws java.lang.NullPointerException if the file path is
       * equal to null.
       */
      public File normalize(String path) throws IOException {
          String orig = path;
  
          path = path.replace('/', File.separatorChar)
              .replace('\\', File.separatorChar);
  
          // make sure we are dealing with an absolute path
          int colon = path.indexOf(":");
  
          if (!onNetWare) {
              if (!path.startsWith(File.separator)
                  && !(path.length() >= 2
                      && Character.isLetter(path.charAt(0))
                      && colon == 1)) {
                  String msg = path + " is not an absolute path";
                  throw new IOException(msg);
              }
          } else {
              if (!path.startsWith(File.separator)
                  && (colon == -1)) {
                  String msg = path + " is not an absolute path";
                  throw new IOException(msg);
              }
          }
  
          boolean dosWithDrive = false;
          String root = null;
          // Eliminate consecutive slashes after the drive spec
          if ((!onNetWare && path.length() >= 2
                  && Character.isLetter(path.charAt(0))
                  && path.charAt(1) == ':')
              || (onNetWare && colon > -1)) {
  
              dosWithDrive = true;
  
              char[] ca = path.replace('/', '\\').toCharArray();
              StringBuffer sbRoot = new StringBuffer();
              for (int i = 0; i < colon; i++) {
                  sbRoot.append(Character.toUpperCase(ca[i]));
              }
              sbRoot.append(':');
              if (colon + 1 < path.length()) {
                  sbRoot.append(File.separatorChar);
              }
              root = sbRoot.toString();
  
              // Eliminate consecutive slashes after the drive spec
              StringBuffer sbPath = new StringBuffer();
              for (int i = colon + 1; i < ca.length; i++) {
                  if ((ca[i] != '\\')
                      || (ca[i] == '\\' && ca[i - 1] != '\\')) {
                      sbPath.append(ca[i]);
                  }
              }
              path = sbPath.toString().replace('\\', File.separatorChar);
  
          } else {
              if (path.length() == 1) {
                  root = File.separator;
                  path = "";
              } else if (path.charAt(1) == File.separatorChar) {
                  // UNC drive
                  root = File.separator + File.separator;
                  path = path.substring(2);
              } else {
                  root = File.separator;
                  path = path.substring(1);
              }
          }
  
          Stack s = new Stack();
          s.push(root);
          StringTokenizer tok = new StringTokenizer(path, File.separator);
          while (tok.hasMoreTokens()) {
              String thisToken = tok.nextToken();
              if (".".equals(thisToken)) {
                  continue;
              } else if ("..".equals(thisToken)) {
                  if (s.size() < 2) {
                      throw new IOException("Cannot resolve path " + orig);
                  } else {
                      s.pop();
                  }
              } else { // plain component
                  s.push(thisToken);
              }
          }
  
          StringBuffer sb = new StringBuffer();
          for (int i = 0; i < s.size(); i++) {
              if (i > 1) {
                  // not before the filesystem root and not after it, since root
                  // already contains one
                  sb.append(File.separatorChar);
              }
              sb.append(s.elementAt(i));
          }
  
  
          path = sb.toString();
          if (dosWithDrive) {
              path = path.replace('/', '\\');
          }
          return new File(path);
      }
  
  }
  
  
  
  1.1                  
avalon/composition/impl/src/java/org/apache/avalon/composition/util/Resource.java
  
  Index: Resource.java
  ===================================================================
  /*
   * Copyright  2000-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.avalon.composition.util;
  
  
  /**
   * describes a File or a ZipEntry
   *
   * this class is meant to be used by classes needing to record path
   * and date/time information about a file, a zip entry or some similar
   * resource (URL, archive in a version control repository, ...)
   *
   * @author Apache Ant Development Team (Levy-Lamber)
   * @author <a href="mailto:[EMAIL PROTECTED]">Avalon Development Team</a>
   * @version $Revision: 1.1 $ $Date: 2004/04/19 18:12:12 $
   */
  public class Resource {
      private String name = null;
      private boolean exists = true;
      private long lastmodified = 0;
      private boolean directory = false;
  
      /**
       * default constructor
       */
      public Resource() {
      }
  
      /**
       * only sets the name.
       *
       * <p>This is a dummy, used for not existing resources.</p>
       *
       * @param name relative path of the resource.  Expects
       * &quot;/&quot; to be used as the directory separator.
       */
      public Resource(String name) {
          this(name, false, 0, false);
      }
  
      /**
       * sets the name, lastmodified flag, and exists flag
       *
       * @param name relative path of the resource.  Expects
       * &quot;/&quot; to be used as the directory separator.
       */
      public Resource(String name, boolean exists, long lastmodified) {
          this(name, exists, lastmodified, false);
      }
  
      /**
       * @param name relative path of the resource.  Expects
       * &quot;/&quot; to be used as the directory separator.
       */
      public Resource(String name, boolean exists, long lastmodified,
                      boolean directory) {
          this.name = name;
          this.exists = exists;
          this.lastmodified = lastmodified;
          this.directory = directory;
      }
  
      /**
       * name attribute will contain the path of a file relative to the
       * root directory of its fileset or the recorded path of a zip
       * entry.
       *
       * <p>example for a file with fullpath /var/opt/adm/resource.txt
       * in a file set with root dir /var/opt it will be
       * adm/resource.txt.</p>
       *
       * <p>&quot;/&quot; will be used as the directory separator.</p>
       */
      public String getName() {
          return name;
      }
  
      /**
       * @param name relative path of the resource.  Expects
       * &quot;/&quot; to be used as the directory separator.
       */
      public void setName(String name) {
          this.name = name;
      }
      /**
       * the exists attribute tells whether a file exists
       */
      public boolean isExists() {
          return exists;
      }
  
      public void setExists(boolean exists) {
          this.exists = exists;
      }
  
      /**
       * tells the modification time in milliseconds since 01.01.1970 of
       *
       * @return 0 if the resource does not exist to mirror the behavior
       * of [EMAIL PROTECTED] java.io.File File}.
       */
      public long getLastModified() {
          return !exists || lastmodified < 0 ? 0 : lastmodified;
      }
  
      public void setLastModified(long lastmodified) {
          this.lastmodified = lastmodified;
      }
      /**
       * tells if the resource is a directory
       * @return boolean flag indicating if the resource is a directory
       */
      public boolean isDirectory() {
          return directory;
      }
  
      public void setDirectory(boolean directory) {
          this.directory = directory;
      }
  
      /**
       * @return copy of this
       */
      public Object clone() {
          try {
              return super.clone();
          } catch (CloneNotSupportedException e) {
              throw new Error("CloneNotSupportedException for a "
                              + "Clonable Resource caught?");
          }
      }
  
      /**
       * delegates to a comparison of names.
       */
      public int compareTo(Object other) {
          if (!(other instanceof Resource)) {
              throw new IllegalArgumentException("Can only be compared with "
                                                 + "Resources");
          }
          Resource r = (Resource) other;
          return getName().compareTo(r.getName());
      }
  
  }
  
  
  
  1.1                  
avalon/composition/impl/src/java/org/apache/avalon/composition/util/ScannerUtils.java
  
  Index: ScannerUtils.java
  ===================================================================
  /*
   * Copyright  2000-2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   *
   */
  
  package org.apache.avalon.composition.util;
  
  import java.io.File;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
  
  
  /**
   * <p>This is a utility class used by DirectoryScanner.</p>
   * <p>This is a Singleton.</p>
   *
   * @author Apache Ant Development Team (Kuiper, Umasankar, Atherton)
   * @author <a href="mailto:[EMAIL PROTECTED]">Avalon Development Team</a>
   * @version $Revision: 1.1 $ $Date: 2004/04/19 18:12:12 $
   */
  public class ScannerUtils {
      private static ScannerUtils instance = new ScannerUtils();
  
      /**
       * Private Constructor
       */
      private ScannerUtils() {
      }
  
      /**
       * Retrieves the instance of the Singleton.
       * @return singleton instance
       */
      public static ScannerUtils getInstance() {
          return instance;
      }
  
      /**
       * Tests whether or not a given path matches the start of a given
       * pattern up to the first "**".
       * <p>
       * This is not a general purpose test and should only be used if you
       * can live with false positives. For example, <code>pattern=**\a</code>
       * and <code>str=b</code> will yield <code>true</code>.
       *
       * @param pattern The pattern to match against. Must not be
       *                <code>null</code>.
       * @param str     The path to match, as a String. Must not be
       *                <code>null</code>.
       *
       * @return whether or not a given path matches the start of a given
       * pattern up to the first "**".
       */
      public static boolean matchPatternStart(String pattern, String str) {
          return matchPatternStart(pattern, str, true);
      }
  
      /**
       * Tests whether or not a given path matches the start of a given
       * pattern up to the first "**".
       * <p>
       * This is not a general purpose test and should only be used if you
       * can live with false positives. For example, <code>pattern=**\a</code>
       * and <code>str=b</code> will yield <code>true</code>.
       *
       * @param pattern The pattern to match against. Must not be
       *                <code>null</code>.
       * @param str     The path to match, as a String. Must not be
       *                <code>null</code>.
       * @param isCaseSensitive Whether or not matching should be performed
       *                        case sensitively.
       *
       * @return whether or not a given path matches the start of a given
       * pattern up to the first "**".
       */
      public static boolean matchPatternStart(String pattern, String str,
                                              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;
          }
  
          String[] patDirs = tokenizePathAsArray(pattern);
          String[] strDirs = tokenizePathAsArray(str);
  
          int patIdxStart = 0;
          int patIdxEnd = patDirs.length - 1;
          int strIdxStart = 0;
          int strIdxEnd = strDirs.length - 1;
  
          // up to first '**'
          while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
              String patDir = patDirs[patIdxStart];
              if (patDir.equals("**")) {
                  break;
              }
              if (!match(patDir, strDirs[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;
          }
      }
  
      /**
       * Tests whether or not a given path matches a given pattern.
       *
       * @param pattern The pattern to match against. Must not be
       *                <code>null</code>.
       * @param str     The path to match, as a String. Must not be
       *                <code>null</code>.
       *
       * @return <code>true</code> if the pattern matches against the string,
       *         or <code>false</code> otherwise.
       */
      public static boolean matchPath(String pattern, String str) {
          return matchPath(pattern, str, true);
      }
  
      /**
       * Tests whether or not a given path matches a given pattern.
       *
       * @param pattern The pattern to match against. Must not be
       *                <code>null</code>.
       * @param str     The path to match, as a String. Must not be
       *                <code>null</code>.
       * @param isCaseSensitive Whether or not matching should be performed
       *                        case sensitively.
       *
       * @return <code>true</code> if the pattern matches against the string,
       *         or <code>false</code> otherwise.
       */
      public static boolean matchPath(String pattern, String str,
                                      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;
          }
  
          String[] patDirs = tokenizePathAsArray(pattern);
          String[] strDirs = tokenizePathAsArray(str);
  
          int patIdxStart = 0;
          int patIdxEnd = patDirs.length - 1;
          int strIdxStart = 0;
          int strIdxEnd = strDirs.length - 1;
  
          // up to first '**'
          while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
              String patDir = patDirs[patIdxStart];
              if (patDir.equals("**")) {
                  break;
              }
              if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
                  patDirs = null;
                  strDirs = null;
                  return false;
              }
              patIdxStart++;
              strIdxStart++;
          }
          if (strIdxStart > strIdxEnd) {
              // String is exhausted
              for (int i = patIdxStart; i <= patIdxEnd; i++) {
                  if (!patDirs[i].equals("**")) {
                      patDirs = null;
                      strDirs = null;
                      return false;
                  }
              }
              return true;
          } else {
              if (patIdxStart > patIdxEnd) {
                  // String not exhausted, but pattern is. Failure.
                  patDirs = null;
                  strDirs = null;
                  return false;
              }
          }
  
          // up to last '**'
          while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
              String patDir = patDirs[patIdxEnd];
              if (patDir.equals("**")) {
                  break;
              }
              if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
                  patDirs = null;
                  strDirs = null;
                  return false;
              }
              patIdxEnd--;
              strIdxEnd--;
          }
          if (strIdxStart > strIdxEnd) {
              // String is exhausted
              for (int i = patIdxStart; i <= patIdxEnd; i++) {
                  if (!patDirs[i].equals("**")) {
                      patDirs = null;
                      strDirs = null;
                      return false;
                  }
              }
              return true;
          }
  
          while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
              int patIdxTmp = -1;
              for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
                  if (patDirs[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 = patDirs[patIdxStart + j + 1];
                                  String subStr = strDirs[strIdxStart + i + j];
                                  if (!match(subPat, subStr, isCaseSensitive)) {
                                      continue strLoop;
                                  }
                              }
  
                              foundIdx = strIdxStart + i;
                              break;
                          }
  
              if (foundIdx == -1) {
                  patDirs = null;
                  strDirs = null;
                  return false;
              }
  
              patIdxStart = patIdxTmp;
              strIdxStart = foundIdx + patLength;
          }
  
          for (int i = patIdxStart; i <= patIdxEnd; i++) {
              if (!patDirs[i].equals("**")) {
                  patDirs = null;
                  strDirs = null;
                  return false;
              }
          }
  
          return true;
      }
  
      /**
       * Tests whether or not a string matches against a pattern.
       * The pattern may contain two special characters:<br>
       * '*' means zero or more characters<br>
       * '?' means one and only one character
       *
       * @param pattern The pattern to match against.
       *                Must not be <code>null</code>.
       * @param str     The string which must be matched against the pattern.
       *                Must not be <code>null</code>.
       *
       * @return <code>true</code> if the string matches against the pattern,
       *         or <code>false</code> otherwise.
       */
      public static boolean match(String pattern, String str) {
          return match(pattern, str, true);
      }
  
      /**
       * Tests whether or not a string matches against a pattern.
       * The pattern may contain two special characters:<br>
       * '*' means zero or more characters<br>
       * '?' means one and only one character
       *
       * @param pattern The pattern to match against.
       *                Must not be <code>null</code>.
       * @param str     The string which must be matched against the pattern.
       *                Must not be <code>null</code>.
       * @param isCaseSensitive Whether or not matching should be performed
       *                        case sensitively.
       *
       *
       * @return <code>true</code> if the string matches against the pattern,
       *         or <code>false</code> otherwise.
       */
      public static boolean match(String pattern, String str,
                                  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;
      }
  
      /**
       * Breaks a path up into a Vector of path elements, tokenizing on
       * <code>File.separator</code>.
       *
       * @param path Path to tokenize. Must not be <code>null</code>.
       *
       * @return a Vector of path elements from the tokenized path
       */
      public static Vector tokenizePath (String path) {
          return tokenizePath(path, File.separator);
      }
  
      /**
       * Breaks a path up into a Vector of path elements, tokenizing on
       *
       * @param path Path to tokenize. Must not be <code>null</code>.
       * @param separator the separator against which to tokenize.
       *
       * @return a Vector of path elements from the tokenized path
       * @since Ant 1.6
       */
      public static Vector tokenizePath (String path, String separator) {
          Vector ret = new Vector();
          StringTokenizer st = new StringTokenizer(path, separator);
          while (st.hasMoreTokens()) {
              ret.addElement(st.nextToken());
          }
          return ret;
      }
  
      /**
       * Same as [EMAIL PROTECTED] #tokenizePath tokenizePath} but hopefully faster.
       */
      private static String[] tokenizePathAsArray(String path) {
          char sep = File.separatorChar;
          int start = 0;
          int len = path.length();
          int count = 0;
          for (int pos = 0; pos < len; pos++) {
              if (path.charAt(pos) == sep) {
                  if (pos != start) {
                      count++;
                  }
                  start = pos + 1;
              }
          }
          if (len != start) {
              count++;
          }
          String[] l = new String[count];
          count = 0;
          start = 0;
          for (int pos = 0; pos < len; pos++) {
              if (path.charAt(pos) == sep) {
                  if (pos != start) {
                      String tok = path.substring(start, pos);
                      l[count++] = tok;
                  }
                  start = pos + 1;
              }
          }
          if (len != start) {
              String tok = path.substring(start);
              l[count/*++*/] = tok;
          }
          return l;
      }
  
  
      /**
       * Returns dependency information on these two files. If src has been
       * modified later than target, it returns true. If target doesn't exist,
       * it likewise returns true. Otherwise, target is newer than src and
       * is not out of date, thus the method returns false. It also returns
       * false if the src file doesn't even exist, since how could the
       * target then be out of date.
       *
       * @param src the original file
       * @param target the file being compared against
       * @param granularity the amount in seconds of slack we will give in
       *        determining out of dateness
       * @return whether the target is out of date
       */
      public static boolean isOutOfDate(File src, File target, int granularity) {
          if (!src.exists()) {
              return false;
          }
          if (!target.exists()) {
              return true;
          }
          if ((src.lastModified() - granularity) > target.lastModified()) {
              return true;
          }
          return false;
      }
  
      /**
       * Returns dependency information on these two resources. If src has been
       * modified later than target, it returns true. If target doesn't exist,
       * it likewise returns true. Otherwise, target is newer than src and
       * is not out of date, thus the method returns false. It also returns
       * false if the src file doesn't even exist, since how could the
       * target then be out of date.
       *
       * @param src the original resource
       * @param target the resource being compared against
       * @param granularity the amount in seconds of slack we will give in
       *        determining out of dateness
       * @return whether the target is out of date
       */
      public static boolean isOutOfDate(Resource src, Resource target,
                                        int granularity) {
          if (!src.isExists()) {
              return false;
          }
          if (!target.isExists()) {
              return true;
          }
          if ((src.getLastModified() - granularity) > target.getLastModified()) {
              return true;
          }
          return false;
      }
  
      /**
       * "Flattens" a string by removing all whitespace (space, tab, linefeed,
       * carriage return, and formfeed). This uses StringTokenizer and the
       * default set of tokens as documented in the single arguement constructor.
       *
       * @param input a String to remove all whitespace.
       * @return a String that has had all whitespace removed.
       */
      public static String removeWhitespace(String input) {
          StringBuffer result = new StringBuffer();
          if (input != null) {
              StringTokenizer st = new StringTokenizer(input);
              while (st.hasMoreTokens()) {
                  result.append(st.nextToken());
              }
          }
          return result.toString();
      }
  
      /**
       * Tests if a string contains stars or question marks
       * @param input a String which one wants to test for containing wildcard
       * @return true if the string contains at least a star or a question mark
       */
      public static boolean hasWildcards(String input) {
          return (input.indexOf('*') != -1 || input.indexOf('?') != -1);
      }
  
      /**
       * removes from a pattern all tokens to the right containing wildcards
       * @param input the input string
       * @return the leftmost part of the pattern without wildcards
       */
      public static String rtrimWildcardTokens(String input) {
          Vector v = tokenizePath(input, File.separator);
          StringBuffer sb = new StringBuffer();
          for (int counter = 0; counter < v.size(); counter++) {
              if (hasWildcards((String) v.elementAt(counter))) {
                  break;
              }
              if (counter > 0) {
                  sb.append(File.separator);
              }
              sb.append((String) v.elementAt(counter));
          }
          return sb.toString();
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to