summaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
authorwisberg <wisberg>2002-12-16 17:09:36 +0000
committerwisberg <wisberg>2002-12-16 17:09:36 +0000
commitc3300283ecc397d26ad9dfe31d1710ec45db2af0 (patch)
treee9acb7f3d33c1499975cec9ef3cc7ea151078344 /util
parent3cde920c3f7eb8241bf569007e25225d80b43c0f (diff)
downloadaspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.tar.gz
aspectj-c3300283ecc397d26ad9dfe31d1710ec45db2af0.zip
initial version
Diffstat (limited to 'util')
-rw-r--r--util/src/.cvsignore1
-rw-r--r--util/src/org/aspectj/util/CollectionUtil.java60
-rw-r--r--util/src/org/aspectj/util/ConfigParser.java290
-rw-r--r--util/src/org/aspectj/util/FileUtil.java1048
-rw-r--r--util/src/org/aspectj/util/FuzzyBoolean.java180
-rw-r--r--util/src/org/aspectj/util/LangUtil.java781
-rw-r--r--util/src/org/aspectj/util/LineReader.java212
-rw-r--r--util/src/org/aspectj/util/NonLocalExit.java39
-rw-r--r--util/src/org/aspectj/util/PartialOrder.java213
-rw-r--r--util/src/org/aspectj/util/Reflection.java106
-rw-r--r--util/src/org/aspectj/util/StreamPrintWriter.java101
-rw-r--r--util/src/org/aspectj/util/TypeSafeEnum.java38
-rw-r--r--util/testsrc/UtilModuleTests.java30
-rw-r--r--util/testsrc/org/aspectj/util/FileUtilTest.java377
-rw-r--r--util/testsrc/org/aspectj/util/LangUtilTest.java266
-rw-r--r--util/testsrc/org/aspectj/util/UtilTests.java32
16 files changed, 3774 insertions, 0 deletions
diff --git a/util/src/.cvsignore b/util/src/.cvsignore
new file mode 100644
index 000000000..a3f0b1b77
--- /dev/null
+++ b/util/src/.cvsignore
@@ -0,0 +1 @@
+*.lst
diff --git a/util/src/org/aspectj/util/CollectionUtil.java b/util/src/org/aspectj/util/CollectionUtil.java
new file mode 100644
index 000000000..637362c1c
--- /dev/null
+++ b/util/src/org/aspectj/util/CollectionUtil.java
@@ -0,0 +1,60 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+
+import java.util.*;
+
+public class CollectionUtil {
+ public static final String[] NO_STRINGS = new String[0];
+
+
+ public static List getListInMap(Map map, Object key) {
+ List list = (List)map.get(key);
+ if (list == null) {
+ list = new ArrayList();
+ map.put(key, list);
+ }
+ return list;
+ }
+
+ public static SortedSet getSortedSetInMap(Map map, Object key) {
+ SortedSet list = (SortedSet)map.get(key);
+ if (list == null) {
+ list = new TreeSet();
+ map.put(key, list);
+ }
+ return list;
+ }
+
+ public static Set getSetInMap(Map map, Object key) {
+ Set list = (Set)map.get(key);
+ if (list == null) {
+ list = new HashSet();
+ map.put(key, list);
+ }
+ return list;
+ }
+
+ public static Map getMapInMap(Map map, Object key) {
+ Map list = (Map)map.get(key);
+ if (list == null) {
+ list = new HashMap();
+ map.put(key, list);
+ }
+ return list;
+ }
+
+}
diff --git a/util/src/org/aspectj/util/ConfigParser.java b/util/src/org/aspectj/util/ConfigParser.java
new file mode 100644
index 000000000..dab133510
--- /dev/null
+++ b/util/src/org/aspectj/util/ConfigParser.java
@@ -0,0 +1,290 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+
+package org.aspectj.util;
+
+import java.util.*;
+import java.io.*;
+
+public class ConfigParser {
+ Location location;
+ protected List files = new LinkedList();
+ private boolean fileParsed = false;
+
+ public List getFiles() { return files; }
+
+ public void parseCommandLine(String[] argsArray) throws ParseException {
+ location = new CommandLineLocation();
+ LinkedList args = new LinkedList();
+ for (int i = 0; i < argsArray.length; i++) {
+ args.add(new Arg(argsArray[i], location));
+ }
+ parseArgs(args);
+ }
+
+ public void parseConfigFile(File configFile) throws ParseException {
+ if (fileParsed == true) {
+ throw new ParseException("The file has already been parsed.", null);
+ } else {
+ parseConfigFileHelper(configFile);
+ }
+ }
+
+ /**
+ * @throws ParseException if the config file has already been prased.
+ */
+ private void parseConfigFileHelper(File configFile) {
+ if (!configFile.exists()) {
+ showError("file does not exist: " + configFile.getPath());
+ return;
+ }
+
+ LinkedList args = new LinkedList();
+ int lineNum = 0;
+
+ try {
+ BufferedReader stream =
+ new BufferedReader(new FileReader(configFile));
+ String line = null;
+ while ( (line = stream.readLine()) != null) {
+ lineNum += 1;
+ line = stripWhitespaceAndComments(line);
+ if (line.length() == 0) continue;
+ args.add(new Arg(line, new SourceLocation(configFile, lineNum)));
+ }
+ } catch (IOException e) {
+ location = new SourceLocation(configFile, lineNum);
+ showError("error reading config file: " + e.toString());
+ }
+ parseArgs(args);
+ fileParsed = true;
+ }
+
+ File getCurrentDir() {
+ return location.getDirectory();
+ }
+
+ String stripSingleLineComment(String s, String commentString) {
+ int commentStart = s.indexOf(commentString);
+ if (commentStart == -1) return s;
+ else return s.substring(0, commentStart);
+ }
+
+ String stripWhitespaceAndComments(String s) {
+ s = stripSingleLineComment(s, "//");
+ s = stripSingleLineComment(s, "#");
+ s = s.trim();
+ if (s.startsWith("\"") && s.endsWith("\"")) {
+ s = s.substring(1, s.length()-1);
+ }
+ return s;
+ }
+
+
+ /** ??? We would like to call a showNonFatalError method here
+ * to show all errors in config files before aborting the compilation
+ */
+ protected void addFile(File sourceFile) {
+ if (!sourceFile.isFile()) {
+ showError("source file does not exist: " + sourceFile.getPath());
+ }
+
+ files.add(sourceFile);
+ }
+
+ void addFileOrPattern(File sourceFile) {
+ if (sourceFile.getName().equals("*.java")) {
+ addFiles(sourceFile.getParentFile(), new FileFilter() {
+ public boolean accept(File f) {
+ return f != null && f.getName().endsWith(".java");
+ }});
+ } else if (sourceFile.getName().equals("*.aj")) {
+ addFiles(sourceFile.getParentFile(), new FileFilter() {
+ public boolean accept(File f) {
+ return f != null && f.getName().endsWith(".aj");
+ }});
+ } else {
+ addFile(sourceFile);
+ }
+ }
+
+ void addFiles(File dir, FileFilter filter) {
+ if (dir == null) dir = new File(System.getProperty("user.dir"));
+
+ if (!dir.isDirectory()) {
+ showError("can't find " + dir.getPath());
+ }
+
+ File[] files = dir.listFiles(filter);
+ if (files.length == 0) {
+ showWarning("no matching files found in: " + dir);
+ }
+
+ for (int i = 0; i < files.length; i++) {
+ addFile(files[i]);
+ }
+ }
+
+ protected void parseOption(String arg, LinkedList args) {
+ showWarning("unrecognized option: " + arg);
+ }
+
+ protected void showWarning(String message) {
+ if (location != null) {
+ message += " at " + location.toString();
+ }
+ System.err.println(message);
+ }
+
+ protected void showError(String message) {
+ throw new ParseException(message, location);
+ }
+
+ void parseArgs(LinkedList args) {
+ while (args.size() > 0) parseOneArg(args);
+ }
+
+ protected Arg removeArg(LinkedList args) {
+ if (args.size() == 0) {
+ showError("value missing");
+ return null;
+ } else {
+ return (Arg)args.removeFirst();
+ }
+ }
+
+ protected String removeStringArg(LinkedList args) {
+ Arg arg = removeArg(args);
+ if (arg == null) return null;
+ return arg.getValue();
+ }
+
+ boolean isSourceFileName(String s) {
+ if (s.endsWith(".java")) return true;
+ if (s.endsWith(".aj")) return true;
+ if (s.endsWith(".ajava")) {
+ showWarning(".ajava is deprecated, replace with .aj or .java: " + s);
+ return true;
+ }
+ return false;
+ }
+
+ void parseOneArg(LinkedList args) {
+ Arg arg = removeArg(args);
+ String v = arg.getValue();
+ location = arg.getLocation();
+ if (v.startsWith("@")) {
+ parseImportedConfigFile(v.substring(1));
+ } else if (v.equals("-argfile")) {
+ parseConfigFileHelper(makeFile(removeArg(args).getValue()));
+ } else if (isSourceFileName(v)) {
+ addFileOrPattern(makeFile(v));
+ } else {
+ parseOption(arg.getValue(), args);
+ }
+ }
+
+ protected void parseImportedConfigFile(String relativeFilePath) {
+ parseConfigFileHelper(makeFile(relativeFilePath));
+ }
+
+ public File makeFile(String name) {
+ return makeFile(getCurrentDir(), name);
+ }
+
+ File makeFile(File dir, String name) {
+ name = name.replace('/', File.separatorChar);
+ File ret = new File(name);
+ if (dir == null || ret.isAbsolute()) return ret;
+ return new File(dir, name);
+ }
+
+
+ protected static class Arg {
+ private Location location;
+ private String value;
+ public Arg(String value, Location location) {
+ this.value = value;
+ this.location = location;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public void setLocation(Location location) {
+ this.location = location;
+ }
+
+ public String getValue() { return value; }
+ public Location getLocation() { return location; }
+ }
+
+ static abstract class Location {
+ public abstract File getFile();
+ public abstract File getDirectory();
+ public abstract int getLine();
+ public abstract String toString();
+ }
+
+ static class SourceLocation extends Location {
+ private int line;
+ private File file;
+ public SourceLocation(File file, int line) {
+ this.line = line;
+ this.file = file;
+ }
+
+ public File getFile() { return file; }
+ public File getDirectory() { return file.getParentFile(); }
+ public int getLine() { return line; }
+
+ public String toString() {
+ return file.getPath()+":"+line;
+ }
+ }
+
+ static class CommandLineLocation extends Location {
+ public File getFile() {
+ return new File(System.getProperty("user.dir"));
+ }
+
+ public File getDirectory() {
+ return new File(System.getProperty("user.dir"));
+ }
+ public int getLine() { return -1; }
+ public String toString() {
+ return "command-line";
+ }
+ }
+
+ public static class ParseException extends RuntimeException {
+ private Location location;
+
+ public ParseException(String message, Location location) {
+ super(message);
+ this.location = location;
+ }
+
+ public int getLine() {
+ if (location == null) return -1;
+ return location.getLine();
+ }
+ public File getFile() {
+ if (location == null) return null;
+ return location.getFile();
+ }
+ }
+}
diff --git a/util/src/org/aspectj/util/FileUtil.java b/util/src/org/aspectj/util/FileUtil.java
new file mode 100644
index 000000000..a0d445cfe
--- /dev/null
+++ b/util/src/org/aspectj/util/FileUtil.java
@@ -0,0 +1,1048 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.util;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.zip.*;
+import java.util.zip.ZipFile;
+
+
+/**
+ *
+ */
+public class FileUtil {
+ /** unmodifiable List of String source file suffixes (including leading ".") */
+ public static final List SOURCE_SUFFIXES
+ = Collections.unmodifiableList(Arrays.asList(new String[] { ".java", ".aj"}));
+
+ final static int[] INT_RA = new int[0];
+
+ /** accept all files */
+ public static final FileFilter ALL = new FileFilter() {
+ public boolean accept(File f) { return true; }
+ };
+
+ /** @return true if file path has a zip/jar suffix */
+ public static boolean hasZipSuffix(File file) {
+ return ((null != file) && hasZipSuffix(file.getPath()));
+ }
+
+ /** @return true if path ends with .zip or .jar */
+ public static boolean hasZipSuffix(String path) {
+ return ((null != path) && (0 != zipSuffixLength(path)));
+ }
+
+ /** @return 0 if file has no zip/jar suffix or 4 otherwise */
+ public static int zipSuffixLength(File file) {
+ return (null == file ? 0 : zipSuffixLength(file.getPath()));
+ }
+
+ /** @return 0 if no zip/jar suffix or 4 otherwise */
+ public static int zipSuffixLength(String path) {
+ return (null == path ? 0
+ : path.endsWith(".zip") ? 4
+ : path.endsWith(".jar") ? 4 : 0);
+ }
+
+ /** @return true if file path has a source suffix */
+ public static boolean hasSourceSuffix(File file) {
+ return ((null != file) && hasSourceSuffix(file.getPath()));
+ }
+
+ /** @return true if path ends with .java or .aj */
+ public static boolean hasSourceSuffix(String path) {
+ return ((null != path) && (0 != sourceSuffixLength(path)));
+ }
+
+ /** @return 0 if file has no source suffix or the length of the suffix otherwise */
+ public static int sourceSuffixLength(File file) {
+ return (null == file ? 0 : sourceSuffixLength(file.getPath()));
+ }
+
+ /** @return 0 if no source suffix or the length of the suffix otherwise */
+ public static int sourceSuffixLength(String path) {
+ if (LangUtil.isEmpty(path)) {
+ return 0;
+ }
+
+ for (Iterator iter = SOURCE_SUFFIXES.iterator(); iter.hasNext();) {
+ String suffix = (String) iter.next();
+ if (path.endsWith(suffix)
+ || path.toLowerCase().endsWith(suffix)) {
+ return suffix.length();
+ }
+ }
+ return 0;
+ }
+
+ /** @return true if this is a readable directory */
+ public static boolean canReadDir(File dir) {
+ return ((null != dir) && dir.canRead() && dir.isDirectory());
+ }
+
+ /** @return true if this is a readable file */
+ public static boolean canReadFile(File file) {
+ return ((null != file) && file.canRead() && file.isFile());
+ }
+
+ /** @return true if dir is a writable directory */
+ public static boolean canWriteDir(File dir) {
+ return ((null != dir) && dir.canWrite() && dir.isDirectory());
+ }
+
+ /** @return true if this is a writable file */
+ public static boolean canWriteFile(File file) {
+ return ((null != file) && file.canWrite() && file.isFile());
+ }
+
+ /** @throws IllegalArgumentException unless file is readable and not a directory */
+ public static void throwIaxUnlessCanReadFile(File file, String label) {
+ if (!canReadFile(file)) {
+ throw new IllegalArgumentException(label + " not readable file: " + file);
+ }
+ }
+
+ /** @throws IllegalArgumentException unless dir is a readable directory */
+ public static void throwIaxUnlessCanReadDir(File dir, String label) {
+ if (!canReadDir(dir)) {
+ throw new IllegalArgumentException(label + " not readable dir: " + dir);
+ }
+ }
+
+ /** @throws IllegalArgumentException unless file is readable and not a directory */
+ public static void throwIaxUnlessCanWriteFile(File file, String label) {
+ if (!canWriteFile(file)) {
+ throw new IllegalArgumentException(label + " not writable file: " + file);
+ }
+ }
+
+ /** @throws IllegalArgumentException unless dir is a readable directory */
+ public static void throwIaxUnlessCanWriteDir(File dir, String label) {
+ if (!canWriteDir(dir)) {
+ throw new IllegalArgumentException(label + " not writable dir: " + dir);
+ }
+ }
+
+ /** @return array same length as input, with String paths */
+ public static String[] getPaths(File[] files) {
+ if ((null == files) || (0 == files.length)) {
+ return new String[0];
+ }
+ String[] result = new String[files.length];
+ for (int i = 0; i < result.length; i++) {
+ if (null != files[i]) {
+ result[i] = files[i].getPath();
+ }
+ }
+ return result;
+ }
+
+ /** @return array same length as input, with String paths */
+ public static String[] getPaths(List files) {
+ final int size = (null == files ? 0 : files.size());
+ if (0 == size) {
+ return new String[0];
+ }
+ String[] result = new String[size];
+ for (int i = 0; i < size; i++) {
+ File file = (File) files.get(i);
+ if (null != file) {
+ result[i] = file.getPath();
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Extract the name of a class from the path to its file.
+ * If the basedir is null, then the class is assumed to be in
+ * the default package unless the classFile has one of the
+ * top-level suffixes { com, org, java, javax } as a parent directory.
+ * @param basedir the File of the base directory (prefix of classFile)
+ * @param classFile the File of the class to extract the name for
+ * @throws IllegalArgumentException if classFile is null or does not end with
+ * ".class" or a non-null basedir is not a prefix of classFile
+ */
+ public static String fileToClassName(File basedir, File classFile) {
+ LangUtil.throwIaxIfNull(classFile, "classFile");
+ String classFilePath = normalizedPath(classFile);
+ if (!classFilePath.endsWith(".class")) {
+ String m = classFile + " does not end with .class";
+ throw new IllegalArgumentException(m);
+ }
+ classFilePath = classFilePath.substring(0, classFilePath.length()-6);
+ if (null != basedir) {
+ String basePath = normalizedPath(basedir);
+ if (!classFilePath.startsWith(basePath)) {
+ String m = classFile + " does not start with " + basedir;
+ throw new IllegalArgumentException(m);
+ }
+ classFilePath = classFilePath.substring(basePath.length()+1);
+ } else {
+ final String[] suffixes = new String[] { "com", "org", "java", "javax"};
+ boolean found = false;
+ for (int i = 0; !found && (i < suffixes.length); i++) {
+ int loc = classFilePath.indexOf(suffixes[i] + "/");
+ if ((0 == loc)
+ || ((-1 != loc) && ('/' == classFilePath.charAt(loc-1)))) {
+ classFilePath = classFilePath.substring(loc);
+ found = true;
+ }
+ }
+ if (!found) {
+ int loc = classFilePath.lastIndexOf("/");
+ if (-1 != loc) { // treat as default package
+ classFilePath = classFilePath.substring(loc+1);
+ }
+ }
+ }
+ return classFilePath.replace('/', '.');
+ }
+
+ /**
+ * Normalize path for comparisons by rendering absolute,
+ * clipping basedir prefix,
+ * trimming and changing '\\' to '/'
+ * @param file the File with the path to normalize
+ * @param basedir the File for the prefix of the file to normalize - ignored if null
+ * @return "" if null or normalized path otherwise
+ * @throws IllegalArgumentException if basedir is not a prefix of file
+ */
+ public static String normalizedPath(File file, File basedir) {
+ String filePath = normalizedPath(file);
+ if (null != basedir) {
+ String basePath = normalizedPath(basedir);
+ if (filePath.startsWith(basePath)) {
+ filePath = filePath.substring(basePath.length());
+ if (filePath.startsWith("/")) {
+ filePath = filePath.substring(1);
+ }
+ }
+ }
+ return filePath;
+ }
+
+ /**
+ * Flatten File[] to String.
+ * @param files the File[] of paths to flatten - null ignored
+ * @param infix the String infix to use - null treated as File.pathSeparator
+ */
+ public static String flatten(File[] files, String infix) {
+ if (LangUtil.isEmpty(files)) {
+ return "";
+ }
+ return flatten(getPaths(files), infix);
+ }
+
+ /**
+ * Flatten File[] to String.
+ * @param files the File[] of paths to flatten - null ignored
+ * @param infix the String infix to use - null treated as File.pathSeparator
+ */
+ public static String flatten(String[] paths, String infix) {
+ if (null == infix) {
+ infix = File.pathSeparator;
+ }
+ StringBuffer result = new StringBuffer();
+ boolean first = true;
+ for (int i = 0; i < paths.length; i++) {
+ String path = paths[i];
+ if (null == path) {
+ continue;
+ }
+ if (first) {
+ first = false;
+ } else {
+ result.append(infix);
+ }
+ result.append(path);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Normalize path for comparisons by rendering absolute
+ * trimming and changing '\\' to '/'
+ * @return "" if null or normalized path otherwise
+ */
+ public static String normalizedPath(File file) {
+ return (null == file ? "" : weakNormalize(file.getAbsolutePath()));
+ }
+
+ /**
+ * Weakly normalize path for comparisons by
+ * trimming and changing '\\' to '/'
+ */
+ public static String weakNormalize(String path) {
+ if (null != path) {
+ path = path.replace('\\', '/').trim();
+ }
+ return path;
+ }
+
+ /** @return array same length as input, with String absolute paths */
+ public static String[] getAbsolutePaths(File[] files) {
+ if ((null == files) || (0 == files.length)) {
+ return new String[0];
+ }
+ String[] result = new String[files.length];
+ for (int i = 0; i < result.length; i++) {
+ if (null != files[i]) {
+ result[i] = files[i].getAbsolutePath();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Recursively delete the contents of dir, but not the dir itself
+ * @return the total number of files deleted
+ */
+ public static int deleteContents(File dir) {
+ return deleteContents(dir, ALL);
+ }
+
+ /**
+ * Recursively delete some contents of dir, but not the dir itself.
+ * This deletes any subdirectory which is empty after its files
+ * are deleted.
+ * @return the total number of files deleted
+ */
+ public static int deleteContents(File dir, FileFilter filter) {
+ return deleteContents(dir, filter, true);
+ }
+
+ /**
+ * Recursively delete some contents of dir, but not the dir itself.
+ * If deleteEmptyDirs is true, this deletes any subdirectory
+ * which is empty after its files are deleted.
+ * @param dir the File directory (if a file, the the file is deleted)
+ * @return the total number of files deleted
+ */
+ public static int deleteContents(File dir, FileFilter filter,
+ boolean deleteEmptyDirs) {
+ if (null == dir) {
+ throw new IllegalArgumentException("null dir");
+ }
+ if ((!dir.exists()) || (!dir.canWrite())) {
+ return 0;
+ }
+ if (!dir.isDirectory()) {
+ dir.delete();
+ return 1;
+ }
+ String[] fromFiles = dir.list();
+ int result = 0;
+ for (int i = 0; i < fromFiles.length; i++) {
+ String string = fromFiles[i];
+ File file = new File(dir, string);
+ if ((null == filter) || filter.accept(file)) {
+ if (file.isDirectory()) {
+ result += deleteContents(file, filter, deleteEmptyDirs);
+ if (deleteEmptyDirs && (0 == file.list().length)) {
+ file.delete();
+ }
+ } else {
+ file.delete();
+ result++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copy contents of fromDir into toDir
+ * @param fromDir must exist and be readable
+ * @param toDir must exist or be creatable and be writable
+ * @return the total number of files copied
+ */
+ public static int copyDir(File fromDir, File toDir) throws IOException {
+ return copyDir(fromDir, toDir, null, null);
+ }
+
+ /**
+ * Recursively copy files in fromDir (with any fromSuffix) to toDir,
+ * replacing fromSuffix with toSuffix if any.
+ * This silently ignores dirs and files that are not readable
+ * but throw IOException for directories that are not writable.
+ * This does not clean out the original contents of toDir.
+ * (subdirectories are not renamed per directory rules)
+ * @param fromSuffix select files with this suffix - select all if null or empty
+ * @param toSuffix replace fromSuffix with toSuffix in the destination file
+ * name - ignored if null or empty,
+ * appended to name if fromSuffix is null or empty
+ * @return the total number of files copied
+ */
+ public static int copyDir(File fromDir, File toDir,
+ final String fromSuffix, String toSuffix) throws IOException {
+ return copyDir(fromDir, toDir, fromSuffix, toSuffix, (FileFilter) null);
+ }
+
+ /** map name to result, removing any fromSuffix and adding any toSuffix */
+ private static String map(String name, String fromSuffix, String toSuffix) {
+ if (null != name) {
+ if (null != fromSuffix) {
+ name = name.substring(0, name.length()-fromSuffix.length());
+ }
+ if (null != toSuffix) {
+ name = name + toSuffix;
+ }
+ }
+ return name;
+ }
+
+ /**
+ * Recursively copy files in fromDir (with any fromSuffix) to toDir,
+ * replacing fromSuffix with toSuffix if any,
+ * and adding the destination file to any collector.
+ * This silently ignores dirs and files that are not readable
+ * but throw IOException for directories that are not writable.
+ * This does not clean out the original contents of toDir.
+ * (subdirectories are not renamed per directory rules)
+ * This calls any delegate FilenameFilter to collect any selected file.
+ * @param fromSuffix select files with this suffix - select all if null or empty
+ * @param toSuffix replace fromSuffix with toSuffix in the destination file
+ * name - ignored if null or empty,
+ * appended to name if fromSuffix is null or empty
+ * @param collector the List sink for destination files - ignored if null
+ * @return the total number of files copied
+ */
+ public static int copyDir(File fromDir, File toDir, final String fromSuffix,
+ final String toSuffix, final List collector) throws IOException {
+ //int before = collector.size();
+ if (null == collector) {
+ return copyDir(fromDir, toDir, fromSuffix, toSuffix);
+ } else {
+ FileFilter collect = new FileFilter() {
+ public boolean accept(File pathname) {
+ return collector.add(pathname);
+ }
+ };
+ return copyDir(fromDir, toDir, fromSuffix, toSuffix, collect);
+ }
+ }
+
+ /**
+ * Recursively copy files in fromDir (with any fromSuffix) to toDir,
+ * replacing fromSuffix with toSuffix if any.
+ * This silently ignores dirs and files that are not readable
+ * but throw IOException for directories that are not writable.
+ * This does not clean out the original contents of toDir.
+ * (subdirectories are not renamed per directory rules)
+ * This calls any delegate FilenameFilter to collect any selected file.
+ * @param fromSuffix select files with this suffix - select all if null or empty
+ * @param toSuffix replace fromSuffix with toSuffix in the destination file
+ * name - ignored if null or empty,
+ * appended to name if fromSuffix is null or empty
+ * @return the total number of files copied
+ */
+ public static int copyDir(File fromDir, File toDir, final String fromSuffix,
+ final String toSuffix, final FileFilter delegate) throws IOException {
+
+ if ((null == fromDir) || (!fromDir.canRead())) {
+ return 0;
+ }
+ final boolean haveSuffix = ((null != fromSuffix) && (0 < fromSuffix.length()));
+ final int slen = (!haveSuffix ? 0 : fromSuffix.length());
+
+ if (!toDir.exists()) {
+ toDir.mkdirs();
+ }
+ final String[] fromFiles;
+ if (!haveSuffix) {
+ fromFiles = fromDir.list();
+ } else {
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return (new File(dir, name).isDirectory()
+ || (name.endsWith(fromSuffix)));
+ }
+ };
+ fromFiles = fromDir.list(filter);
+ }
+ int result = 0;
+ final int MAX = (null == fromFiles ? 0 : fromFiles.length);
+ for (int i = 0; i < MAX; i++) {
+ String filename = fromFiles[i];
+ File fromFile = new File(fromDir, filename);
+ if (fromFile.canRead()) {
+ if (fromFile.isDirectory()) {
+ result += copyDir(fromFile, new File(toDir, filename), fromSuffix, toSuffix, delegate);
+ } else if (fromFile.isFile()) {
+ if (haveSuffix) {
+ filename = filename.substring(0, filename.length()-slen);
+ }
+ if (null != toSuffix) {
+ filename = filename + toSuffix;
+ }
+ File targetFile = new File(toDir, filename);
+ if ((null == delegate) || delegate.accept(targetFile)) {
+ copyFile(fromFile, targetFile);
+ }
+ result++;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Recursively list files in srcDir.
+ * @return ArrayList with String paths of File under srcDir (relative to srcDir)
+ */
+ public static String[] listFiles(File srcDir) {
+ ArrayList result = new ArrayList();
+ if ((null != srcDir) && srcDir.canRead()) {
+ listFiles(srcDir, null, result);
+ }
+ return (String[]) result.toArray(new String[0]);
+ }
+
+ private static void listFiles(final File baseDir, String dir, ArrayList result) {
+ final String dirPrefix = (null == dir ? "" : dir + "/");
+ final File dirFile = (null == dir ? baseDir : new File(baseDir.getPath() + "/" + dir));
+ final String[] files = dirFile.list();
+ for (int i = 0; i < files.length; i++) {
+ File f = new File(dirFile, files[i]);
+ String path = dirPrefix + files[i];
+ if (f.isDirectory()) {
+ listFiles(baseDir, path, result);
+ } else {
+ result.add(path);
+ }
+ }
+ }
+
+ public static final FileFilter aspectjSourceFileFilter = new FileFilter() {
+ public boolean accept(File pathname) {
+ String name = pathname.getName().toLowerCase();
+ return name.endsWith(".java") || name.endsWith(".aj");
+ }
+ };
+
+
+ /**
+ * Recursively list files in srcDir.
+ * @return ArrayList with String paths of File under srcDir (relative to srcDir)
+ */
+ public static File[] listFiles(File srcDir, FileFilter fileFilter) {
+ ArrayList result = new ArrayList();
+ if ((null != srcDir) && srcDir.canRead()) {
+ listFiles(srcDir, result, fileFilter);
+ }
+ return (File[]) result.toArray(new File[result.size()]);
+ }
+
+ private static void listFiles(final File baseDir, ArrayList result, FileFilter filter) {
+ File[] files = baseDir.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ File f = files[i];
+ if (f.isDirectory()) {
+ listFiles(f, result, filter);
+ } else {
+ if (filter.accept(f)) result.add(f);
+ }
+ }
+ }
+
+ /**
+ * Convert String[] paths to File[] as offset of base directory
+ * @param basedir the non-null File base directory for File to create with paths
+ * @param paths the String[] of paths to create
+ * @return File[] with same length as paths
+ */
+ public static File[] getBaseDirFiles(
+ File basedir,
+ String[] paths) {
+ return getBaseDirFiles(basedir, paths, (String[]) null);
+ }
+
+ /**
+ * Convert String[] paths to File[] as offset of base directory
+ * @param basedir the non-null File base directory for File to create with paths
+ * @param paths the String[] of paths to create
+ * @param suffixes the String[] of suffixes to limit sources to - ignored if null
+ * @return File[] with same length as paths
+ */
+ public static File[] getBaseDirFiles(
+ File basedir,
+ String[] paths,
+ String[] suffixes) {
+ LangUtil.throwIaxIfNull(basedir, "basedir");
+ LangUtil.throwIaxIfNull(paths, "paths");
+ File[] result = null;
+ if (!LangUtil.isEmpty(suffixes)) {
+ ArrayList list = new ArrayList();
+ for (int i = 0; i < paths.length; i++) {
+ boolean listed = false;
+ String path = paths[i];
+ for (int j = 0; !listed && (j < suffixes.length); j++) {
+ String suffix = suffixes[j];
+ if (listed = path.endsWith(suffix)) {
+ list.add(new File(basedir, paths[i]));
+ }
+ }
+ }
+ result = (File[]) list.toArray(new File[0]);
+ } else {
+ result = new File[paths.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = new File(basedir, paths[i]);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copy files from source dir into destination directory,
+ * creating any needed directories. This differs from copyDir in not
+ * being recursive; each input with the source dir creates a full path.
+ * @param srcDir an existing, readable directory containing relativePaths files
+ * @param relativePaths a set of paths relative to srcDir to readable File to copy
+ * @param destDir an existing, writable directory to copy files to
+ * @throws IllegalArgumentException if input invalid, IOException if operations fail
+ */
+ public static File[] copyFiles(File srcDir, String[] relativePaths, File destDir)
+ throws IllegalArgumentException, IOException {
+ final String[] paths = relativePaths;
+ throwIaxUnlessCanReadDir(srcDir, "srcDir");
+ throwIaxUnlessCanWriteDir(destDir, "destDir");
+ LangUtil.throwIaxIfNull(paths, "relativePaths");
+ File[] result = new File[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ String path = paths[i];
+ LangUtil.throwIaxIfNull(path, "relativePaths-entry");
+ File src = new File(srcDir, relativePaths[i]);
+ throwIaxUnlessCanReadFile(src, "src-entry");
+ File dest = new File(destDir, path);
+ File destParent = dest.getParentFile();
+ if (!destParent.exists()) {
+ destParent.mkdirs();
+ }
+ LangUtil.throwIaxIfFalse(canWriteDir(destParent), "dest-entry-parent");
+ copyFile(src, dest);
+ result[i] = dest;
+ }
+ return result;
+ }
+
+ /** copy fromFile to toFile */
+ public static void copyFile(File fromFile, File toFile) throws IOException {
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ try {
+ in = new FileInputStream(fromFile);
+ out = new FileOutputStream(toFile);
+ copyStream(in, out);
+ } finally {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ }
+ }
+
+ /** do line-based copying */
+ public static void copyStream(DataInputStream in, PrintStream out) throws IOException {
+ LangUtil.throwIaxIfNull(in, "in");
+ LangUtil.throwIaxIfNull(in, "out");
+ String s;
+ while (null != (s = in.readLine())) {
+ out.println(s);
+ }
+ }
+
+ public static void copyStream(InputStream in, OutputStream out) throws IOException {
+ final int MAX = 4096;
+ byte[] buf = new byte[MAX];
+ for (int bytesRead = in.read(buf, 0, MAX);
+ bytesRead != -1;
+ bytesRead = in.read(buf, 0, MAX)) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ public static void copyStream(Reader in, Writer out) throws IOException {
+ final int MAX = 4096;
+ char[] buf = new char[MAX];
+ for (int bytesRead = in.read(buf, 0, MAX);
+ bytesRead != -1;
+ bytesRead = in.read(buf, 0, MAX)) {
+ out.write(buf, 0, bytesRead);
+ }
+ }
+
+ private static boolean isValidFileName(String input) {
+ return ((null != input) && (-1 == input.indexOf(File.pathSeparator)));
+ }
+
+ /**
+ * Make a new child directory of parent
+ * @param parent a File for the parent (writable)
+ * @param child a prefix for the child directory
+ * @return a File dir that exists with parentDir as the parent file or null
+ */
+ public static File makeNewChildDir(File parent, String child) {
+ if (null == parent || ! parent.canWrite() || !parent.isDirectory()) {
+ throw new IllegalArgumentException("bad parent: " + parent);
+ } else if (null == child) {
+ child = "makeNewChildDir";
+ } else if (!isValidFileName(child)) {
+ throw new IllegalArgumentException("bad child: " + child);
+ }
+ File result = new File(parent, child);
+ int safety = 1000;
+ for (String suffix = FileUtil.randomFileString();
+ ((0 < --safety) && result.exists());
+ suffix = FileUtil.randomFileString()) {
+ result = new File(parent, child+suffix);
+ }
+ if ((null == result) || result.exists()) {
+ System.err.println("exhausted files for child dir in " + parent);
+ return null;
+ }
+ return ((result.mkdirs() && result.exists()) ? result : null);
+ }
+
+ /**
+ * Make a new temporary directory in the same directory
+ * that the system uses for temporary files, or if
+ * that files, in the current directory.
+ * @param name the preferred (simple) name of the directory - may be null.
+ * @return File of an existing new temp dir, or null if unable to create
+ */
+ public static File getTempDir(String name) {
+ if (null == name) {
+ name = "FileUtil_getTempDir";
+ } else if (!isValidFileName(name)) {
+ throw new IllegalArgumentException(" invalid: " + name);
+ }
+ File result = null;
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("ignoreMe", ".txt");
+ File tempParent = tempFile.getParentFile();
+ result = makeNewChildDir(tempParent, name);
+ } catch (IOException t) {
+ result = makeNewChildDir(new File("."), name);
+ } finally {
+ if (null != tempFile) {
+ tempFile.delete();
+ }
+ }
+ return result;
+ }
+
+ public static URL[] getFileURLs(File[] files) { // XXX prints errors to System.err
+ if ((null == files) || (0 == files.length)) {
+ return new URL[0];
+ }
+ URL[] result = new URL[files.length]; // XXX dangerous non-copy...
+ for (int i = 0; i < result.length; i++) {
+ result[i] = getFileURL(files[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Get URL for a File.
+ * This appends "/" for directories.
+ * prints errors to System.err
+ * @param file the File to convert to URL (not null)
+ */
+ public static URL getFileURL(File file) {
+ LangUtil.throwIaxIfNull(file, "file");
+ URL result = null;
+ try {
+ String url = "file:" + file.getAbsolutePath().replace('\\', '/');
+ result = new URL(url + (file.isDirectory() ? "/" : ""));
+ } catch (MalformedURLException e) {
+ String m = "Util.makeURL(\"" + file.getPath() + "\" MUE " + e.getMessage();
+ System.err.println(m);
+ }
+ return result;
+ }
+
+
+
+ /**
+ * Write contents to file, returning null on success or error message otherwise.
+ * This tries to make any necessary parent directories first.
+ */
+ public static String writeAsString(File file, String contents) {
+ LangUtil.throwIaxIfNull(file, "file");
+ if (null == contents) {
+ contents = "";
+ }
+ Writer out = null;
+ try {
+ File parentDir = file.getParentFile();
+ if (!parentDir.exists() && !parentDir.mkdirs()) {
+ return "unable to make parent dir for " + file;
+ }
+ Reader in = new StringReader(contents);
+ out = new FileWriter(file);
+ FileUtil.copyStream(in, out);
+ return null;
+ } catch (IOException e) {
+ return LangUtil.unqualifiedClassName(e) + " writing " + file
+ + ": " + e.getMessage();
+ } finally {
+ if (null != out) {
+ try { out.close(); }
+ catch (IOException e) {} // ignored
+ }
+ }
+ }
+
+
+ /**
+ * Reads an int array with our encoding
+ */
+ public static int[] readIntArray(DataInputStream s) throws IOException {
+ int len = s.readInt();
+ int[] ret = new int[len];
+ for (int i=0; i < len; i++) ret[i] = s.readInt();
+ return ret;
+ }
+
+
+ /**
+ * Reads an int array with our encoding
+ */
+ public static void writeIntArray(DataOutputStream s, int[] a) throws IOException {
+ int len = a.length;
+ s.writeInt(len);
+ for (int i=0; i < len; i++) s.writeInt(a[i]);
+ }
+
+
+
+
+ /**
+ * Returns the contents of this file as a String
+ */
+ public static String readAsString(File file) throws IOException {
+ BufferedReader r = new BufferedReader(new FileReader(file));
+ StringBuffer b = new StringBuffer();
+ while (true) {
+ int ch = r.read();
+ if (ch == -1) break;
+ b.append((char)ch);
+ }
+ r.close();
+ return b.toString();
+ }
+
+ /**
+ * Returns the contents of this stream as a String
+ */
+ public static String readAsString(InputStream in) throws IOException {
+ BufferedReader r = new BufferedReader(new InputStreamReader(in));
+ StringBuffer b = new StringBuffer();
+ while (true) {
+ int ch = r.read();
+ if (ch == -1) break;
+ b.append((char)ch);
+ }
+ in.close();
+ r.close();
+ return b.toString();
+ }
+
+
+ /**
+ * Returns the contents of this file as a byte[]
+ */
+ public static byte[] readAsByteArray(File file) throws IOException {
+ FileInputStream in = new FileInputStream(file);
+ byte[] ret = FileUtil.readAsByteArray(in);
+ in.close();
+ return ret;
+ }
+
+
+ /**
+ * Reads this input stream and returns contents as a byte[]
+ */
+ public static byte[] readAsByteArray(InputStream inStream) throws IOException {
+ int size = 1024;
+ byte[] ba = new byte[size];
+ int readSoFar = 0;
+
+ while (true) {
+ int nRead = inStream.read(ba, readSoFar, size-readSoFar);
+ if (nRead == -1) break;
+ readSoFar += nRead;
+ if (readSoFar == size) {
+ int newSize = size * 2;
+ byte[] newBa = new byte[newSize];
+ System.arraycopy(ba, 0, newBa, 0, size);
+ ba = newBa;
+ size = newSize;
+ }
+ }
+
+ byte[] newBa = new byte[readSoFar];
+ System.arraycopy(ba, 0, newBa, 0, readSoFar);
+ return newBa;
+ }
+ final static String FILECHARS = "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ /** @return String usable in a File name which is random */
+
+ /** @return semi-random String of length 6 usable as filename suffix */
+ static String randomFileString() {
+ final double FILECHARS_length = FILECHARS.length();
+ final int LEN = 6;
+ final char[] result = new char[LEN];
+ int index = (int) (Math.random() * 6d);
+ for (int i = 0; i < LEN; i++) {
+ if (index >= LEN) {
+ index = 0;
+ }
+ result[index++] = FILECHARS.charAt((int) (Math.random() * FILECHARS_length));
+ }
+ return new String(result);
+ }
+
+ public static InputStream getStreamFromZip(String zipFile, String name) {
+ try {
+ ZipFile zf = new ZipFile(zipFile);
+ try {
+ ZipEntry entry = zf.getEntry(name);
+ return zf.getInputStream(entry);
+ } finally {
+ //??? is it safe not to close this zf.close();
+ }
+ } catch (IOException ioe) {
+ return null;
+ }
+ }
+
+
+ public static void extractJar(String zipFile, String outDir) throws IOException {
+ ZipInputStream zs = new ZipInputStream(new FileInputStream(zipFile));
+ ZipEntry entry;
+ while ( (entry = zs.getNextEntry()) != null) {
+ if (entry.isDirectory()) continue;
+ byte[] in = readAsByteArray(zs);
+
+ File outFile = new File(outDir + "/" + entry.getName());
+ //if (!outFile.getParentFile().exists())
+ //System.err.println("parent: " + outFile.getParentFile());
+ //System.err.println("parent: " + outFile.getParentFile());
+ outFile.getParentFile().mkdirs();
+ FileOutputStream os = new FileOutputStream(outFile);
+ os.write(in);
+ os.close();
+ zs.closeEntry();
+ }
+ zs.close();
+ }
+
+ private FileUtil() { throw new Error("utility class"); }
+
+
+
+ /**
+ * Do line-based search for literal text in source files,
+ * returning file:line where found.
+ * @param sought the String text to seek in the file
+ * @param sources the List of String paths to the source files
+ * @param listAll if false, only list first match in file
+ * @param errorSink the PrintStream to print any errors to (one per line)
+ * (use null to silently ignore errors)
+ * @return List of String of the form file:line for each found entry
+ * (never null, might be empty)
+ */
+ public static List lineSeek(String sought, List sources, boolean listAll,
+ PrintStream errorSink) {
+ if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sources)) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList result = new ArrayList();
+ for (Iterator iter = sources.iterator(); iter.hasNext();) {
+ String path = (String) iter.next();
+ String error = lineSeek(sought, path, listAll, result);
+ if ((null != error) && (null != errorSink)) {
+ errorSink.println(error);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Do line-based search for literal text in source file,
+ * returning line where found as a String
+ * in the form {sourcePath}:line:column submitted to the
+ * collecting parameter sink.
+ * Any error is rendered to String and returned as the result.
+ *
+ * @param sought the String text to seek in the file
+ * @param sources the List of String paths to the source files
+ * @param listAll if false, only list first match in file
+ * @param List sink the List for String entries of the form {sourcePath}:line:column
+ * @return String error if any, or add String entries to sink
+ */
+ public static String lineSeek(String sought, String sourcePath, boolean listAll,
+ ArrayList sink) {
+ if (LangUtil.isEmpty(sought) || LangUtil.isEmpty(sourcePath)) {
+ return "nothing sought";
+ }
+ if (LangUtil.isEmpty(sourcePath)) {
+ return "no sourcePath";
+ }
+ final File file = new File(sourcePath);
+ if (!file.canRead() || !file.isFile()) {
+ return "sourcePath not a readable file";
+ }
+ int lineNum = 0;
+ FileReader fin = null;
+ try {
+ fin = new FileReader(file);
+ BufferedReader reader = new BufferedReader(fin);
+ String line;
+ while (null != (line = reader.readLine())) {
+ lineNum++;
+ int loc = line.indexOf(sought);
+ if (-1 != loc) {
+ sink.add(sourcePath + ":" + lineNum + ":" + loc);
+ if (!listAll) {
+ break;
+ }
+ }
+ }
+ } catch (IOException e) {
+ return LangUtil.unqualifiedClassName(e) + " reading " + sourcePath
+ + ":" + lineNum;
+ } finally {
+ try { if (null != fin) fin.close(); }
+ catch (IOException e) {} // ignore
+ }
+ return null;
+ }
+
+ public static BufferedOutputStream makeOutputStream(File file) throws FileNotFoundException {
+ File parent = file.getParentFile();
+ if (parent != null) parent.mkdirs();
+ return new BufferedOutputStream(new FileOutputStream(file));
+ }
+
+}
diff --git a/util/src/org/aspectj/util/FuzzyBoolean.java b/util/src/org/aspectj/util/FuzzyBoolean.java
new file mode 100644
index 000000000..adb66bb41
--- /dev/null
+++ b/util/src/org/aspectj/util/FuzzyBoolean.java
@@ -0,0 +1,180 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.util.*;
+
+
+/** This class implements boolean that include a "maybe"
+ */
+
+public abstract class FuzzyBoolean {
+ public abstract boolean alwaysTrue();
+ public abstract boolean alwaysFalse();
+ public abstract boolean maybeTrue();
+ public abstract boolean maybeFalse();
+
+ public abstract FuzzyBoolean and(FuzzyBoolean other);
+ public abstract FuzzyBoolean or(FuzzyBoolean other);
+ public abstract FuzzyBoolean not();
+
+ private static class YesFuzzyBoolean extends FuzzyBoolean {
+ public boolean alwaysFalse() {
+ return false;
+ }
+
+ public boolean alwaysTrue() {
+ return true;
+ }
+
+
+ public boolean maybeFalse() {
+ return false;
+ }
+
+ public boolean maybeTrue() {
+ return true;
+ }
+
+ public FuzzyBoolean and(FuzzyBoolean other) {
+ return other;
+ }
+
+ public FuzzyBoolean not() {
+ return FuzzyBoolean.NO;
+ }
+
+ public FuzzyBoolean or(FuzzyBoolean other) {
+ return this;
+ }
+
+ public String toString() {
+ return "YES";
+ }
+ }
+ private static class NoFuzzyBoolean extends FuzzyBoolean {
+ public boolean alwaysFalse() {
+ return true;
+ }
+
+ public boolean alwaysTrue() {
+ return false;
+ }
+
+
+ public boolean maybeFalse() {
+ return true;
+ }
+
+ public boolean maybeTrue() {
+ return false;
+ }
+
+ public FuzzyBoolean and(FuzzyBoolean other) {
+ return this;
+ }
+
+ public FuzzyBoolean not() {
+ return FuzzyBoolean.YES;
+ }
+
+ public FuzzyBoolean or(FuzzyBoolean other) {
+ return other;
+ }
+
+ public String toString() {
+ return "NO";
+ }
+ }
+ private static class NeverFuzzyBoolean extends FuzzyBoolean {
+ public boolean alwaysFalse() {
+ return true;
+ }
+
+ public boolean alwaysTrue() {
+ return false;
+ }
+
+
+ public boolean maybeFalse() {
+ return true;
+ }
+
+ public boolean maybeTrue() {
+ return false;
+ }
+
+ public FuzzyBoolean and(FuzzyBoolean other) {
+ return this;
+ }
+
+ public FuzzyBoolean not() {
+ return this;
+ }
+
+ public FuzzyBoolean or(FuzzyBoolean other) {
+ return this;
+ }
+
+ public String toString() {
+ return "NEVER";
+ }
+ }
+
+ private static class MaybeFuzzyBoolean extends FuzzyBoolean {
+ public boolean alwaysFalse() {
+ return false;
+ }
+
+ public boolean alwaysTrue() {
+ return false;
+ }
+
+
+ public boolean maybeFalse() {
+ return true;
+ }
+
+ public boolean maybeTrue() {
+ return true;
+ }
+
+ public FuzzyBoolean and(FuzzyBoolean other) {
+ return other.alwaysFalse() ? other : this;
+ }
+
+ public FuzzyBoolean not() {
+ return this;
+ }
+
+ public FuzzyBoolean or(FuzzyBoolean other) {
+ return other.alwaysTrue() ? other : this;
+ }
+
+ public String toString() {
+ return "MAYBE";
+ }
+ }
+
+ public static final FuzzyBoolean YES = new YesFuzzyBoolean();
+ public static final FuzzyBoolean NO = new NoFuzzyBoolean();
+ public static final FuzzyBoolean MAYBE = new MaybeFuzzyBoolean();
+ public static final FuzzyBoolean NEVER = new NeverFuzzyBoolean();
+
+ public static final FuzzyBoolean fromBoolean(boolean b) {
+ return b ? YES : NO;
+ }
+
+}
diff --git a/util/src/org/aspectj/util/LangUtil.java b/util/src/org/aspectj/util/LangUtil.java
new file mode 100644
index 000000000..0a93721f1
--- /dev/null
+++ b/util/src/org/aspectj/util/LangUtil.java
@@ -0,0 +1,781 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.util;
+
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ *
+ */
+public class LangUtil {
+ /** map from String version to String class implemented in that version or later */
+ private static final Map VM_CLASSES;
+
+ public static final String EOL;
+ static {
+ StringWriter buf = new StringWriter();
+ PrintWriter writer = new PrintWriter(buf);
+ writer.println("");
+ String eol = "\n";
+ try {
+ buf.close();
+ StringBuffer sb = buf.getBuffer();
+ if ((null != sb) || (0 < sb.length())) {
+ eol = buf.toString();
+ }
+ } catch (Throwable t) { }
+ EOL = eol;
+
+ HashMap map = new HashMap();
+ map.put("1.2", "java.lang.ref.Reference");
+ map.put("1.3", "java.lang.reflect.Proxy");
+ map.put("1.4", "java.nio.Buffer");
+
+ VM_CLASSES = Collections.unmodifiableMap(map);
+ }
+
+ /**
+ * Detect whether Java version is supported.
+ * @param version String "1.2" or "1.3" or "1.4"
+ * @return true if the currently-running VM supports the version
+ * @throws IllegalArgumentException if version is not known
+ */
+ public static final boolean supportsJava(String version) {
+ LangUtil.throwIaxIfNull(version, "version");
+ String className = (String) VM_CLASSES.get(version);
+ if (null == className) {
+ throw new IllegalArgumentException("unknown version: " + version);
+ }
+ try {
+ Class.forName(className);
+ return true;
+ } catch (Throwable t) {
+ return false;
+ }
+ }
+
+ /**
+ * Shorthand for "if null, throw IllegalArgumentException"
+ * @throws IllegalArgumentException "null {name}" if o is null
+ */
+ public static final void throwIaxIfNull(final Object o, final String name) {
+ if (null == o) {
+ String message = "null " + (null == name ? "input" : name);
+ throw new IllegalArgumentException(message);
+ }
+ }
+
+ /**
+ * Shorthand for "if not null or not assignable, throw IllegalArgumentException"
+ * @throws IllegalArgumentException "null {name}" if o is null
+ */
+ public static final void throwIaxIfNotAssignable(final Object o, final Class c, final String name) {
+ throwIaxIfNull(o, name);
+ if (null != c) {
+ Class actualClass = o.getClass();
+ if (!c.isAssignableFrom(actualClass)) {
+ String message = name + " not assignable to " + c.getName();
+ throw new IllegalArgumentException(message);
+ }
+ }
+ }
+
+ /**
+ * Shorthand for "if any not null or not assignable, throw IllegalArgumentException"
+ * @throws IllegalArgumentException "{name} is not assignable to {c}"
+ */
+ public static final void throwIaxIfNotAllAssignable(final Collection collection,
+ final Class c, final String name) {
+ throwIaxIfNull(collection, name);
+ if (null != c) {
+ for (Iterator iter = collection.iterator(); iter.hasNext();) {
+ throwIaxIfNotAssignable(iter.next(), c, name);
+
+ }
+ }
+ }
+ /**
+ * Shorthand for "if false, throw IllegalArgumentException"
+ * @throws IllegalArgumentException "{message}" if test is false
+ */
+ public static final void throwIaxIfFalse(final boolean test, final String message) {
+ if (!test) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+
+ /** @return ((null == s) || (0 == s.trim().length())); */
+ public static boolean isEmptyTrimmed(String s) {
+ return ((null == s) || (0 == s.length())
+ || (0 == s.trim().length()));
+ }
+
+ /** @return ((null == s) || (0 == s.length())); */
+ public static boolean isEmpty(String s) {
+ return ((null == s) || (0 == s.length()));
+ }
+
+ /** @return ((null == ra) || (0 == ra.length)) */
+ public static boolean isEmpty(Object[] ra) {
+ return ((null == ra) || (0 == ra.length));
+ }
+
+ /** @return ((null == collection) || (0 == collection.size())) */
+ public static boolean isEmpty(Collection collection) {
+ return ((null == collection) || (0 == collection.size()));
+ }
+
+ /**
+ * Splits <code>text</code> at whitespace.
+ *
+ * @param text <code>String</code> to split.
+ */
+ public static String[] split(String text) {
+ return (String[]) strings(text).toArray(new String[0]);
+ }
+
+ /**
+ * Splits <code>input</code> at commas,
+ * trimming any white space.
+ *
+ * @param text <code>String</code> to split.
+ * @return List of String of elements.
+ */
+ public static List commaSplit(String input) {
+ if (null == input) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList result = new ArrayList();
+
+ if (-1 == input.indexOf(",")) {
+ result.add(input.trim());
+ } else {
+ StringTokenizer st = new StringTokenizer(input, ",");
+ while (st.hasMoreTokens()) {
+ result.add(st.nextToken().trim());
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Splits strings into a <code>List</code> using a
+ * <code>StringTokenizer</code>.
+ *
+ * @param text <code>String</code> to split.
+ */
+ public static List strings(String text) {
+ List strings = new ArrayList();
+ StringTokenizer tok = new StringTokenizer(text);
+ while (tok.hasMoreTokens()) {
+ strings.add(tok.nextToken());
+ }
+ return strings;
+ }
+
+ /** @return a non-null unmodifiable List */
+ public static List safeList(List list) {
+ return (
+ null == list
+ ? Collections.EMPTY_LIST
+ : Collections.unmodifiableList(list));
+ }
+
+ /**
+ * Select from input String[] based on suffix-matching
+ * @param inputs String[] of input - null ignored
+ * @param suffixes String[] of suffix selectors - null ignored
+ * @param ignoreCase if true, ignore case
+ * @return String[] of input that end with any input
+ */
+ public static String[] endsWith(String[] inputs, String[] suffixes, boolean ignoreCase) {
+ if (LangUtil.isEmpty(inputs) || LangUtil.isEmpty(suffixes)) {
+ return new String[0];
+ }
+ if (ignoreCase) {
+ String[] temp = new String[suffixes.length];
+ for (int i = 0; i < temp.length; i++) {
+ String suff = suffixes[i];
+ temp[i] = (null == suff ? null : suff.toLowerCase());
+ }
+ suffixes = temp;
+ }
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < inputs.length; i++) {
+ String input = inputs[i];
+ if (null == input) {
+ continue;
+ }
+ if (!ignoreCase) {
+ input = input.toLowerCase();
+ }
+ for (int j = 0; j < suffixes.length; j++) {
+ String suffix = suffixes[j];
+ if (null == suffix) {
+ continue;
+ }
+ if (input.endsWith(suffix)) {
+ result.add(input);
+ break;
+ }
+ }
+ }
+ return (String[]) result.toArray(new String[0]);
+ }
+
+ /**
+ * copy non-null two-dimensional String[][]
+ * @see extractOptions(String[], String[][])
+ */
+ public static String[][] copyStrings(String[][] in) {
+ String[][] out = new String[in.length][];
+ for (int i = 0; i < out.length; i++) {
+ out[i] = new String[in[i].length];
+ System.arraycopy(in[i], 0, out[i], 0, out[i].length);
+ }
+ return out;
+ }
+
+ /**
+ * Extract options and arguments to input option list, returning remainder.
+ * The input options will be nullified if not found. e.g.,
+ * <pre>String[] options = new String[][] { new String[] { "-verbose" },
+ * new String[] { "-classpath", null } };
+ * String[] args = extractOptions(args, options);
+ * boolean verbose = null != options[0][0];
+ * boolean classpath = options[1][1];</pre>
+ * @param args the String[] input options
+ * @param options the String[][]options to find in the input args - not null
+ * for each String[] component the first subcomponent is the option itself,
+ * and there is one String subcomponent for each additional argument.
+ * @return String[] of args remaining after extracting options to extracted
+ */
+ public static String[] extractOptions(String[] args, String[][] options) {
+ if (LangUtil.isEmpty(args) || LangUtil.isEmpty(options) ) {
+ return args;
+ }
+ BitSet foundSet = new BitSet();
+ String[] result = new String[args.length];
+ int resultIndex = 0;
+ for (int j = 0; j < args.length; j++) {
+ boolean found = false;
+ for (int i = 0; !found && (i < options.length); i++) {
+ String[] option = options[i];
+ LangUtil.throwIaxIfFalse(!LangUtil.isEmpty(option), "options");
+ String sought = option[0];
+ if (found = sought.equals(args[j])) {
+ foundSet.set(i);
+ int doMore = option.length-1;
+ if (0 < doMore) {
+ final int MAX = j + doMore;
+ if (MAX >= args.length) {
+ String s = "expecting " + doMore + " args after ";
+ throw new IllegalArgumentException(s + args[j]);
+ }
+ for (int k = 1; k < option.length; k++) {
+ option[k] = args[++j];
+ }
+ }
+ }
+ }
+ if (!found) {
+ result[resultIndex++] = args[j];
+ }
+ }
+
+ // unset any not found
+ for (int i = 0; i < options.length; i++) {
+ if (!foundSet.get(i)) {
+ options[i][0] = null;
+ }
+ }
+ // fixup remainder
+ if (resultIndex < args.length) {
+ String[] temp = new String[resultIndex];
+ System.arraycopy(result, 0, temp, 0, resultIndex);
+ args = temp;
+ }
+
+ return args;
+ }
+
+ /**
+ * Extract options and arguments to input parameter list, returning remainder.
+ * @param args the String[] input options
+ * @param validOptions the String[] options to find in the input args - not null
+ * @param optionArgs the int[] number of arguments for each option in validOptions
+ * (if null, then no arguments for any option)
+ * @param extracted the List for the matched options
+ * @return String[] of args remaining after extracting options to extracted
+ */
+ public static String[] extractOptions(String[] args, String[] validOptions,
+ int[] optionArgs, List extracted) {
+ if (LangUtil.isEmpty(args)
+ || LangUtil.isEmpty(validOptions) ) {
+ return args;
+ }
+ if (null != optionArgs) {
+ if (optionArgs.length != validOptions.length) {
+ throw new IllegalArgumentException("args must match options");
+ }
+ }
+ String[] result = new String[args.length];
+ int resultIndex = 0;
+ for (int j = 0; j < args.length; j++) {
+ boolean found = false;
+ for (int i = 0; !found && (i < validOptions.length); i++) {
+ String sought = validOptions[i];
+ int doMore = (null == optionArgs ? 0 : optionArgs[i]);
+ if (LangUtil.isEmpty(sought)) {
+ continue;
+ }
+ if (found = sought.equals(args[j])) {
+ if (null != extracted) {
+ extracted.add(sought);
+ }
+ if (0 < doMore) {
+ final int MAX = j + doMore;
+ if (MAX >= args.length) {
+ String s = "expecting " + doMore + " args after ";
+ throw new IllegalArgumentException(s + args[j]);
+ }
+ if (null != extracted) {
+ while (j < MAX) {
+ extracted.add(args[++j]);
+ }
+ } else {
+ j = MAX;
+ }
+ }
+ break;
+ }
+ }
+ if (!found) {
+ result[resultIndex++] = args[j];
+ }
+ }
+ if (resultIndex < args.length) {
+ String[] temp = new String[resultIndex];
+ System.arraycopy(result, 0, temp, 0, resultIndex);
+ args = temp;
+ }
+ return args;
+ }
+
+ /** @return String[] of entries in validOptions found in args */
+ public static String[] selectOptions(String[] args, String[] validOptions) {
+ if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
+ return new String[0];
+ }
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < validOptions.length; i++) {
+ String sought = validOptions[i];
+ if (LangUtil.isEmpty(sought)) {
+ continue;
+ }
+ for (int j = 0; j < args.length; j++) {
+ if (sought.equals(args[j])) {
+ result.add(sought);
+ break;
+ }
+ }
+ }
+ return (String[]) result.toArray(new String[0]);
+ }
+
+ /** @return String[] of entries in validOptions found in args */
+ public static String[] selectOptions(List args, String[] validOptions) {
+ if (LangUtil.isEmpty(args) || LangUtil.isEmpty(validOptions)) {
+ return new String[0];
+ }
+ ArrayList result = new ArrayList();
+ for (int i = 0; i < validOptions.length; i++) {
+ String sought = validOptions[i];
+ if (LangUtil.isEmpty(sought)) {
+ continue;
+ }
+ for (Iterator iter = args.iterator(); iter.hasNext();) {
+ String arg = (String) iter.next();
+ if (sought.equals(arg)) {
+ result.add(sought);
+ break;
+ }
+ }
+ }
+ return (String[]) result.toArray(new String[0]);
+ }
+
+ /**
+ * Generate variants of String[] options by creating an extra set for
+ * each option that ends with "-". If none end with "-", then an
+ * array equal to <code>new String[][] { options }</code> is returned;
+ * if one ends with "-", then two sets are returned,
+ * three causes eight sets, etc.
+ * @return String[][] with each option set.
+ * @throws IllegalArgumentException if any option is null or empty.
+ */
+ public static String[][] optionVariants(String[] options) {
+ if ((null == options) || (0 == options.length)) {
+ return new String[][] { new String[0]};
+ }
+ // be nice, don't stomp input
+ String[] temp = new String[options.length];
+ System.arraycopy(options, 0, temp, 0, temp.length);
+ options = temp;
+ boolean[] dup = new boolean[options.length];
+ int numDups = 0;
+
+ for (int i = 0; i < options.length; i++) {
+ String option = options[i];
+ if (LangUtil.isEmpty(option)) {
+ throw new IllegalArgumentException("empty option at " + i);
+ }
+ if (option.endsWith("-")) {
+ options[i] = option.substring(0, option.length()-1);
+ dup[i] = true;
+ numDups++;
+ }
+ }
+ final String[] NONE = new String[0];
+ final int variants = exp(2, numDups);
+ final String[][] result = new String[variants][];
+ // variant is a bitmap wrt doing extra value when dup[k]=true
+ for (int variant = 0; variant < variants; variant++) {
+ ArrayList next = new ArrayList();
+ int nextOption = 0;
+ for (int k = 0; k < options.length; k++) {
+ if (!dup[k] || (0 != (variant & (1 << (nextOption++))))) {
+ next.add(options[k]);
+ }
+ }
+ result[variant] = (String[]) next.toArray(NONE);
+ }
+ return result;
+ }
+
+ private static int exp(int base, int power) { // not in Math?
+ if (0 > power) {
+ throw new IllegalArgumentException("negative power: " + power);
+ }
+ int result = 1;
+ while (0 < power--) {
+ result *= base;
+ }
+ return result;
+ }
+
+ /**
+ * Make a copy of the array.
+ * @return an array with the same component type as source
+ * containing same elements, even if null.
+ * @throws IllegalArgumentException if source is null
+ */
+ public static final Object[] copy(Object[] source) {
+ LangUtil.throwIaxIfNull(source, "source");
+ final Class c = source.getClass().getComponentType();
+ Object[] result = (Object[]) Array.newInstance(c, source.length);
+ System.arraycopy(source, 0, result, 0, result.length);
+ return result;
+ }
+
+
+ /**
+ * Convert arrays safely. The number of elements in the result
+ * will be 1 smaller for each element that is null or not assignable.
+ * This will use sink if it has exactly the right size.
+ * The result will always have the same component type as sink.
+ * @return an array with the same component type as sink
+ * containing any assignable elements in source (in the same order).
+ * @throws IllegalArgumentException if either is null
+ */
+ public static Object[] safeCopy(Object[] source, Object[] sink) {
+ final Class sinkType = (null == sink
+ ? Object.class
+ : sink.getClass().getComponentType());
+ final int sourceLength = (null == source ? 0 : source.length);
+ final int sinkLength = (null == sink ? 0 : sink.length);
+
+ final int resultSize;
+ ArrayList result = null;
+ if (0 == sourceLength) {
+ resultSize = 0;
+ } else {
+ result = new ArrayList(sourceLength);
+ for (int i = 0; i < sourceLength; i++) {
+ if ((null != source[i])
+ && (sinkType.isAssignableFrom(source[i].getClass()))) {
+ result.add(source[i]);
+ }
+ }
+ resultSize = result.size();
+ }
+ if (resultSize != sinkLength) {
+ sink = (Object[]) Array.newInstance(sinkType, result.size());
+ }
+ if (0 < resultSize) {
+ sink = result.toArray(sink);
+ }
+ return sink;
+ }
+
+ /**
+ * @return a String with the unqualified class name of the class (or "null")
+ */
+ public static String unqualifiedClassName(Class c) {
+ if (null == c) {
+ return "null";
+ }
+ String name = c.getName();
+ int loc = name.lastIndexOf(".");
+ if (-1 != loc) {
+ name = name.substring(1 + loc);
+ }
+ return name;
+ }
+
+ /**
+ * @return a String with the unqualified class name of the object (or "null")
+ */
+ public static String unqualifiedClassName(Object o) {
+ return LangUtil.unqualifiedClassName(null == o ? null : o.getClass());
+ }
+
+ /** render i right-justified with a given width less than about 40 */
+ public static String toSizedString(long i, int width) {
+ String result = "" + i;
+ int size = result.length();
+ if (width > size) {
+ final String pad = " ";
+ final int padLength = pad.length();
+ if (width > padLength) {
+ width = padLength;
+ }
+ int topad = width-size;
+ result = pad.substring(0, topad) + result;
+ }
+ return result;
+ }
+
+ /** clip StringBuffer to maximum number of lines */
+ static String clipBuffer(StringBuffer buffer, int maxLines) {
+ if ((null == buffer) || (1 > buffer.length())) return "";
+ StringBuffer result = new StringBuffer();
+ int j = 0;
+ final int MAX = maxLines;
+ final int N = buffer.length();
+ for (int i = 0, srcBegin = 0; i < MAX; srcBegin += j) {
+ // todo: replace with String variant if/since getting char?
+ char[] chars = new char[128];
+ int srcEnd = srcBegin+chars.length;
+ if (srcEnd >= N) {
+ srcEnd = N-1;
+ }
+ if (srcBegin == srcEnd) break;
+ //log("srcBegin:" + srcBegin + ":srcEnd:" + srcEnd);
+ buffer.getChars(srcBegin, srcEnd, chars, 0);
+ for (j = 0; j < srcEnd-srcBegin/*chars.length*/; j++) {
+ char c = chars[j];
+ if (c == '\n') {
+ i++;
+ j++;
+ break;
+ }
+ }
+ try { result.append(chars, 0, j); }
+ catch (Throwable t) { }
+ }
+ return result.toString();
+ }
+
+ /**
+ * @return "({UnqualifiedExceptionClass}) {message}"
+ */
+ public static String renderExceptionShort(Throwable e) {
+ if (null == e)
+ return "(Throwable) null";
+ return "(" + LangUtil.unqualifiedClassName(e) + ") " + e.getMessage();
+ }
+
+ /**
+ * Renders exception <code>t</code> after unwrapping and
+ * eliding any test packages.
+ * @param t <code>Throwable</code> to print.
+ * @see #maxStackTrace
+ */
+ public static String renderException(Throwable t) {
+ return renderException(t, true);
+ }
+
+ /**
+ * Renders exception <code>t</code>, unwrapping,
+ * optionally eliding and limiting total number of lines.
+ * @param t <code>Throwable</code> to print.
+ * @param elide true to limit to 100 lines and elide test packages
+ * @see StringChecker#TEST_PACKAGES
+ */
+ public static String renderException(Throwable t, boolean elide) {
+ if (null == t) return "null throwable";
+ t = unwrapException(t);
+ StringBuffer stack = stackToString(t, false);
+ if (elide) {
+ elideEndingLines(StringChecker.TEST_PACKAGES, stack, 100);
+ }
+ return stack.toString();
+ }
+
+ /**
+ * Trim ending lines from a StringBuffer,
+ * clipping to maxLines and further removing any number of
+ * trailing lines accepted by checker.
+ * @param checker returns true if trailing line should be elided.
+ * @param stack StringBuffer with lines to elide
+ * @param maxLines int for maximum number of resulting lines
+ */
+ static void elideEndingLines(StringChecker checker, StringBuffer stack, int maxLines) {
+ if (null == checker || (null == stack) || (0 == stack.length())) {
+ return;
+ }
+ final LinkedList lines = new LinkedList();
+ StringTokenizer st = new StringTokenizer(stack.toString(),"\n\r");
+ while (st.hasMoreTokens() && (0 < --maxLines)) {
+ lines.add(st.nextToken());
+ }
+ st = null;
+
+ String line;
+ int elided = 0;
+ while (!lines.isEmpty()) {
+ line = (String) lines.getLast();
+ if (!checker.acceptString(line)) {
+ break;
+ } else {
+ elided++;
+ lines.removeLast();
+ }
+ }
+ if ((elided > 0) || (maxLines < 1)) {
+ final int EOL_LEN = EOL.length();
+ int totalLength = 0;
+ while (!lines.isEmpty()) {
+ totalLength += EOL_LEN + ((String) lines.getFirst()).length();
+ lines.removeFirst();
+ }
+ if (stack.length() > totalLength) {
+ stack.setLength(totalLength);
+ if (elided > 0) {
+ stack.append(" (... " + elided + " lines...)");
+ }
+ }
+ }
+ }
+
+
+ /** Dump message and stack to StringBuffer. */
+ public static StringBuffer stackToString(Throwable throwable, boolean skipMessage) {
+ if (null == throwable) {
+ return new StringBuffer();
+ }
+ StringWriter buf = new StringWriter();
+ PrintWriter writer = new PrintWriter(buf);
+ if (!skipMessage) {
+ writer.println(throwable.getMessage());
+ }
+ throwable.printStackTrace(writer);
+ try { buf.close(); }
+ catch (IOException ioe) {} // ignored
+ return buf.getBuffer();
+ }
+
+
+ /** @return Throwable input or tail of any wrapped exception chain */
+ public static Throwable unwrapException(Throwable t) {
+ if (t instanceof InvocationTargetException) {
+ Throwable thrown = ((InvocationTargetException) t).getTargetException();
+ if (null != thrown) {
+ return unwrapException(thrown);
+ }
+ } else if (t instanceof ClassNotFoundException) {
+ Throwable thrown = ((ClassNotFoundException) t).getException();
+ if (null != thrown) {
+ return unwrapException(thrown);
+ }
+ }
+ // ChainedException
+ // ExceptionInInitializerError
+ return t;
+ }
+
+ /**
+ * Replacement for Arrays.asList(..) which gacks on null
+ * and returns a List in which remove is an unsupported operation.
+ * @param array the Object[] to convert (may be null)
+ * @return the List corresponding to array (never null)
+ */
+ public static List arrayAsList(Object[] array) {
+ if ((null == array) || (1 > array.length)) {
+ return Collections.EMPTY_LIST;
+ }
+ ArrayList list = new ArrayList();
+ list.addAll(Arrays.asList(array));
+ return list;
+ }
+
+
+
+
+ /** check if input contains any packages to elide. */
+ public static class StringChecker {
+ static StringChecker TEST_PACKAGES = new StringChecker( new String[]
+ { "org.aspectj.testing.",
+ "org.eclipse.jdt.internal.junit",
+ "junit.framework.",
+ "org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"
+ });
+
+ String[] infixes;
+
+ /** @param infixes adopted */
+ StringChecker(String[] infixes) {
+ this.infixes = infixes;
+ }
+
+ /** @return true if input contains infixes */
+ public boolean acceptString(String input) {
+ boolean result = false;
+ if (!LangUtil.isEmpty(input)) {
+ for (int i = 0; !result && (i < infixes.length); i++) {
+ result = (-1 != input.indexOf(infixes[i]));
+ }
+ }
+ return result;
+ }
+ }
+}
diff --git a/util/src/org/aspectj/util/LineReader.java b/util/src/org/aspectj/util/LineReader.java
new file mode 100644
index 000000000..622d7b4c9
--- /dev/null
+++ b/util/src/org/aspectj/util/LineReader.java
@@ -0,0 +1,212 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.io.*;
+import java.util.ArrayList;
+
+/**
+ * LineNumberReader which absorbs comments and blank lines
+ * and renders as file:line
+ */
+public class LineReader extends LineNumberReader {
+ /** delimited multi-line output of readToBlankLine */
+ public static final String RETURN= "\n\r";
+
+ private static final String[] NONE = new String[0];
+ private static final String cSCRIPT = "#";
+ private static final String cJAVA = "//";
+ private static final String[] TESTER_LEAD = new String[] {cSCRIPT, cJAVA};
+
+ /**
+ * Convenience factory for tester suite files
+ * @return null if IOException or IllegalArgumentException thrown
+ */
+ public static final LineReader createTester(File file) {
+ return create(file, TESTER_LEAD, null);
+ }
+
+ /**
+ * convenience factory
+ * @return null if IOException or IllegalArgumentException thrown
+ */
+ public static final LineReader create(File file,
+ String[] leadComments, String[] eolComments) {
+ try {
+ FileReader reader = new FileReader(file);
+ return new LineReader(reader, file, leadComments, eolComments);
+ } catch (IllegalArgumentException e) {
+ } catch (IOException e) {
+ }
+ return null;
+ }
+
+ final private File file;
+ final private String[] eolComments;
+ final private String[] leadComments;
+ transient String lastLine;
+
+ /**
+ * @param file the File used to open the FileReader
+ * @param leadComments the String[] to be taken as the start of
+ * comments when they are the first non-blank text on a line -
+ * pass null to signal none.
+ * @param leadComments the String[] to be taken as the start of
+ * comment anywhere on a line - pass null to signal none.
+ *@throws IllegalArgumentException if any String in
+ * leadComments or eolComments is null.
+ */
+ public LineReader(FileReader reader, File file,
+ String[] leadComments, String[] eolComments) {
+ super(reader);
+ this.file = file;
+ this.eolComments = normalize(eolComments);
+ this.leadComments = normalize(leadComments);
+ }
+ public LineReader(FileReader reader, File file) {
+ this(reader, file, null, null);
+ }
+
+ /** @return file:line */
+ public String toString() {
+ return file.getPath() + ":" + getLineNumber();
+ }
+
+ /** @return underlying file */
+ public File getFile() { return file; }
+
+ /**
+ * Reader first..last (inclusive) and return in String[].
+ * This will return (1+(last-first)) elements only if this
+ * reader has not read past the first line and there are last lines
+ * and there are no IOExceptions during reads.
+ * @param first the first line to read - if negative, use 0
+ * @param last the last line to read (inclusive)
+ * - if less than first, use first
+ * @return String[] of first..last (inclusive) lines read or
+ */
+ public String[] readLines(int first, int last) {
+ if (0 > first) first = 0;
+ if (first > last) last = first;
+ ArrayList list = new ArrayList();
+ try {
+ String line = null;
+ while (getLineNumber() < first) {
+ line = readLine();
+ if (null == line) {
+ break;
+ }
+ }
+ if (getLineNumber() > first) {
+ // XXX warn? something else read past line
+ }
+ if ((null != line) && (first == getLineNumber())) {
+ list.add(line);
+ while (last >= getLineNumber()) {
+ line = readLine();
+ if (null == line) {
+ break;
+ }
+ list.add(line);
+ }
+ }
+ } catch (IOException e) {
+ return NONE;
+ }
+ return (String[]) list.toArray(NONE);
+ }
+
+ /** Skip to next blank line
+ * @return the String containing all lines skipped (delimited with RETURN)
+ */
+ public String readToBlankLine() throws IOException {
+ StringBuffer sb = new StringBuffer();
+ String input;
+ while (null != (input = nextLine(false))) { // get next empty line to restart
+ sb.append(input);
+ sb.append(RETURN);// XXX verify/ignore/correct
+ }
+ return sb.toString();
+ }
+
+ /**
+ * lastLine is set only by readClippedLine, not readLine.
+ * @return the last line read, after clipping
+ */
+ public String lastLine() {
+ return lastLine;
+ }
+
+ /**
+ * Get the next line from the input stream, stripping eol and
+ * leading comments.
+ * If emptyLinesOk is true, then this reads past lines which are
+ * empty after omitting comments and trimming until the next non-empty line.
+ * Otherwise, this returns null on reading an empty line.
+ * (The input stream is not exhausted until this
+ * returns null when emptyLines is true.)
+ * @param skipEmpties if true, run to next non-empty line; if false, return next line
+ * @return null if no more lines or got an empty line when they are not ok,
+ * or next non-null, non-empty line in reader,
+ * ignoring comments
+ */
+ public String nextLine(boolean skipEmpties) throws IOException {
+ String result;
+ do {
+ result = readClippedLine();
+ if ((null != result) && skipEmpties && (0 == result.length())) {
+ continue;
+ }
+ return result;
+ } while (true);
+ }
+
+ /** @return null if no more lines or a clipped line otherwise */
+ protected String readClippedLine() throws IOException {
+ String result = readLine();
+ if (result != null) {
+ result = result.trim();
+ int len = result.length();
+ for (int i = 0; ((0 < len) && (i < leadComments.length)); i++) {
+ if (result.startsWith(leadComments[i])) {
+ result = "";
+ len = 0;
+ }
+ }
+ for (int i = 0; ((0 < len) && (i < eolComments.length)); i++) {
+ int loc = result.indexOf(eolComments[i]);
+ if (-1 != loc) {
+ result = result.substring(0, loc);
+ len = result.length();
+ }
+ }
+ }
+ lastLine = result;
+ return result;
+ }
+
+ private String[] normalize(String[] input) {
+ if ((null == input) || (0 == input.length)) return NONE;
+ String[] result = new String[input.length];
+ System.arraycopy(input, 0, result, 0, result.length);
+ for (int i = 0; i < result.length; i++) {
+ if ((null == result[i]) || (0 == result[i].length())) {
+ throw new IllegalArgumentException("empty input at [" + i + "]");
+ }
+ }
+ return result;
+ }
+}
+
diff --git a/util/src/org/aspectj/util/NonLocalExit.java b/util/src/org/aspectj/util/NonLocalExit.java
new file mode 100644
index 000000000..1c75d075d
--- /dev/null
+++ b/util/src/org/aspectj/util/NonLocalExit.java
@@ -0,0 +1,39 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+/**
+ * Throw this when a non-local exit is required (suggested for tests only).
+ */
+public class NonLocalExit extends RuntimeException {
+
+ public static final int SUCCEESS = 0;
+ public static final int FAULURE = 1;
+
+ private int exitCode;
+
+ public NonLocalExit(int exitCode) {
+ this();
+ this.exitCode = exitCode;
+ }
+
+ public NonLocalExit() {
+ super();
+ }
+
+ public int getExitCode() {
+ return exitCode;
+ }
+
+}
diff --git a/util/src/org/aspectj/util/PartialOrder.java b/util/src/org/aspectj/util/PartialOrder.java
new file mode 100644
index 000000000..6051caffd
--- /dev/null
+++ b/util/src/org/aspectj/util/PartialOrder.java
@@ -0,0 +1,213 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.util.*;
+
+
+/** This class implements a partial order
+ *
+ * It includes routines for doing a topo-sort
+ */
+
+public class PartialOrder {
+
+ /** All classes that want to be part of a partial order must implement
+ * PartialOrder.PartialComparable.
+ */
+ public static interface PartialComparable {
+ /**
+ * @returns <ul>
+ * <li>+1 if this is greater than other</li>
+ * <li>-1 if this is less than other</li>
+ * <li>0 if this is not comparable to other</li>
+ * </ul>
+ *
+ * <b> Note: returning 0 from this method doesn't mean the same thing as returning
+ * 0 from java.util.Comparable.compareTo()</b>
+ */
+ public int compareTo(Object other);
+
+ /**
+ * This method can provide a deterministic ordering for elements that
+ * are strictly not comparable. If you have no need for this, this method
+ * can just return 0 whenever called.
+ */
+ public int fallbackCompareTo(Object other);
+ }
+
+ private static class SortObject {
+ PartialComparable object;
+ List/*SortObject*/ smallerObjects = new LinkedList();
+ List/*SortObject*/ biggerObjects = new LinkedList();
+
+ public SortObject(PartialComparable o) {
+ object = o;
+ }
+
+ boolean hasNoSmallerObjects() { return smallerObjects.size() == 0; }
+
+ boolean removeSmallerObject(SortObject o) {
+ smallerObjects.remove(o);
+ return hasNoSmallerObjects();
+ }
+
+ void addDirectedLinks(SortObject other) {
+ int cmp = object.compareTo(other.object);
+ if (cmp == 0) return;
+ if (cmp > 0) {
+ this.smallerObjects.add(other);
+ other.biggerObjects.add(this);
+ } else {
+ this.biggerObjects.add(other);
+ other.smallerObjects.add(this);
+ }
+ }
+
+ public String toString() {
+ return object.toString(); //+smallerObjects+biggerObjects;
+ }
+ }
+
+ private static void addNewPartialComparable(List graph, PartialComparable o) {
+ SortObject so = new SortObject(o);
+ for (Iterator i = graph.iterator(); i.hasNext(); ) {
+ SortObject other = (SortObject)i.next();
+ so.addDirectedLinks(other);
+ }
+ graph.add(so);
+ }
+
+ private static void removeFromGraph(List graph, SortObject o) {
+ for (Iterator i = graph.iterator(); i.hasNext(); ) {
+ SortObject other = (SortObject)i.next();
+
+ if (o == other) i.remove();
+ //??? could use this to build up a new queue of objects with no
+ //??? smaller ones
+ other.removeSmallerObject(o);
+ }
+ }
+
+ /**
+ * @param objects must all implement PartialComparable
+ *
+ * @returns the same members as objects, but sorted according to their partial
+ * order. returns null if the objects are cyclical
+ *
+ */
+ public static List sort(List objects) {
+ // lists of size 0 or 1 don't need any sorting
+ if (objects.size() < 2) return objects;
+
+ //??? we might want to optimize a few other cases of small size
+
+ //??? I don't like creating this data structure, but it does give good
+ //??? separation of concerns.
+ List sortList = new LinkedList(); //objects.size());
+ for (Iterator i = objects.iterator(); i.hasNext(); ) {
+ addNewPartialComparable(sortList, (PartialComparable)i.next());
+ }
+
+ //System.out.println(sortList);
+
+ // now we have built our directed graph
+ // use a simple sort algorithm from here
+ // can increase efficiency later
+ // List ret = new ArrayList(objects.size());
+ final int N = objects.size();
+ for (int index = 0; index < N; index++) {
+ //System.out.println(sortList);
+ //System.out.println("-->" + ret);
+
+ SortObject leastWithNoSmallers = null;
+
+ for (Iterator i = sortList.iterator(); i.hasNext(); ) {
+ SortObject so = (SortObject)i.next();
+ //System.out.println(so);
+ if (so.hasNoSmallerObjects()) {
+ if (leastWithNoSmallers == null ||
+ so.object.fallbackCompareTo(leastWithNoSmallers.object) < 0)
+ {
+ leastWithNoSmallers = so;
+ }
+ }
+ }
+
+ if (leastWithNoSmallers == null) return null;
+
+ removeFromGraph(sortList, leastWithNoSmallers);
+ objects.set(index, leastWithNoSmallers.object);
+ }
+
+ return objects;
+ }
+
+ /***********************************************************************************
+ /* a minimal testing harness
+ ***********************************************************************************/
+ static class Token implements PartialComparable {
+ private String s;
+
+ Token(String s) {
+ this.s = s;
+ }
+
+ public int compareTo(Object other) {
+ Token t = (Token)other;
+
+ int cmp = s.charAt(0) - t.s.charAt(0);
+ if (cmp == 1) return 1;
+ if (cmp == -1) return -1;
+ return 0;
+ }
+
+ public int fallbackCompareTo(Object other) {
+ return -s.compareTo( ((Token)other).s );
+ }
+
+ public String toString() {
+ return s;
+ }
+ }
+
+ public static void main(String[] args) {
+ List l = new ArrayList();
+ l.add(new Token("a1"));
+ l.add(new Token("c2"));
+ l.add(new Token("b3"));
+ l.add(new Token("f4"));
+ l.add(new Token("e5"));
+ l.add(new Token("d6"));
+ l.add(new Token("c7"));
+ l.add(new Token("b8"));
+
+ l.add(new Token("z"));
+ l.add(new Token("x"));
+
+ l.add(new Token("f9"));
+ l.add(new Token("e10"));
+ l.add(new Token("a11"));
+ l.add(new Token("d12"));
+ l.add(new Token("b13"));
+ l.add(new Token("c14"));
+
+ System.out.println(l);
+
+ sort(l);
+
+ System.out.println(l);
+ }
+}
diff --git a/util/src/org/aspectj/util/Reflection.java b/util/src/org/aspectj/util/Reflection.java
new file mode 100644
index 000000000..bee7bd70e
--- /dev/null
+++ b/util/src/org/aspectj/util/Reflection.java
@@ -0,0 +1,106 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.lang.reflect.*;
+import java.lang.reflect.Method;
+
+public class Reflection {
+
+ private Reflection() {
+ }
+
+ public static Object invokestatic(Class class_, String name) {
+ return invokestaticN(class_, name, new Object[0]);
+ }
+
+ public static Object invokestatic(Class class_, String name, Object arg1) {
+ return invokestaticN(class_, name, new Object[] { arg1 });
+ }
+
+ public static Object invokestatic(Class class_, String name, Object arg1, Object arg2) {
+ return invokestaticN(class_, name, new Object[] { arg1, arg2 });
+ }
+
+ public static Object invokestatic(Class class_, String name, Object arg1, Object arg2, Object arg3) {
+ return invokestaticN(class_, name, new Object[] { arg1, arg2, arg3 });
+ }
+
+
+ public static Object invokestaticN(Class class_, String name, Object[] args) {
+ return invokeN(class_, name, null, args);
+ }
+
+
+ public static Object invoke(Class class_, Object target, String name, Object arg1) {
+ return invokeN(class_, name, target, new Object[] { arg1 });
+ }
+
+ public static Object invoke(Class class_, Object target, String name, Object arg1, Object arg2) {
+ return invokeN(class_, name, target, new Object[] { arg1, arg2 });
+ }
+
+ public static Object invoke(Class class_, Object target, String name, Object arg1, Object arg2, Object arg3) {
+ return invokeN(class_, name, target, new Object[] { arg1, arg2, arg3 });
+ }
+
+
+
+
+ public static Object invokeN(Class class_, String name, Object target, Object[] args) {
+ Method meth = getMatchingMethod(class_, name, args);
+ try {
+ return meth.invoke(target, args);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e.toString());
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getTargetException();
+ if (t instanceof Error) throw (Error)t;
+ if (t instanceof RuntimeException) throw (RuntimeException)t;
+ t.printStackTrace();
+ throw new RuntimeException(t.toString());
+ }
+ }
+
+
+ public static Method getMatchingMethod(Class class_, String name, Object[] args) {
+ Method[] meths = class_.getMethods();
+ for (int i=0; i < meths.length; i++) {
+ Method meth = meths[i];
+ if (meth.getName().equals(name) && isCompatible(meth, args)) {
+ return meth;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isCompatible(Method meth, Object[] args) {
+ // ignore methods with overloading other than lengths
+ return meth.getParameterTypes().length == args.length;
+ }
+
+
+
+
+ public static Object getStaticField(Class class_, String name) {
+ try {
+ return class_.getField(name).get(null);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException("unimplemented");
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("unimplemented");
+ }
+ }
+
+}
diff --git a/util/src/org/aspectj/util/StreamPrintWriter.java b/util/src/org/aspectj/util/StreamPrintWriter.java
new file mode 100644
index 000000000..6167e6694
--- /dev/null
+++ b/util/src/org/aspectj/util/StreamPrintWriter.java
@@ -0,0 +1,101 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.io.*;
+
+/**
+ * Used for writing converting text written to an output stream into
+ * a string. Deprecated - use StringWriter:
+ * <pre>
+ * StringWriter sw = new StringWriter();
+ * PrintWriter pw = new PrintWriter(sw, true);
+ * ... write to pw
+ * String result = sw.getBuffer().toString();
+ * </pre>
+ * @deprecated use StringWriter to construct PrintWriter
+ * @author Mik Kersten
+ */
+public class StreamPrintWriter extends PrintWriter {
+ private String contents = "";
+
+ public StreamPrintWriter(Writer out) {
+ super(out);
+ }
+
+ public String getContents() {
+ return contents;
+ }
+
+ public void flushBuffer() {
+ contents = "";
+ super.flush();
+ }
+
+ public void print(char x) {
+ contents += x + "\n";
+ }
+
+ public void print(char[] x) {
+ contents += new String( x );
+ }
+
+ public void print(int x) {
+ contents += x;
+ }
+
+ public void print(String x) {
+ contents += x;
+ }
+
+ public void println(char x) {
+ contents += x + "\n";
+ }
+
+ public void println(char[] x) {
+ contents += new String( x ) + "\n";
+ }
+
+ public void println(int x) {
+ contents += x + "\n";
+ }
+
+ public void println(String x) {
+ contents += x + "\n";
+ }
+
+ public void write( byte[] x ) {
+ contents += new String( x );
+ }
+
+ public void write( byte[] x, int i1, int i2 ) {
+ StringWriter writer = new StringWriter();
+ String s = new String( x );
+ writer.write( s.toCharArray(), i1, i2 );
+ contents += writer.getBuffer().toString();
+ }
+
+ public void write( int c ) {
+ contents += c;
+ }
+
+ public void write( String s ) {
+ contents += s;
+ }
+
+ public void write( String s, int i1, int i2 ) {
+ contents += s;
+ }
+}
diff --git a/util/src/org/aspectj/util/TypeSafeEnum.java b/util/src/org/aspectj/util/TypeSafeEnum.java
new file mode 100644
index 000000000..6980d39c9
--- /dev/null
+++ b/util/src/org/aspectj/util/TypeSafeEnum.java
@@ -0,0 +1,38 @@
+/* *******************************************************************
+ * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import java.io.*;
+
+public class TypeSafeEnum {
+ private byte key;
+ private String name;
+
+ public TypeSafeEnum(String name, int key) {
+ this.name = name;
+ if (key > Byte.MAX_VALUE || key < Byte.MIN_VALUE) {
+ throw new IllegalArgumentException("key doesn't fit into a byte: " + key);
+ }
+ this.key = (byte)key;
+ }
+
+ public String toString() { return name; }
+
+ public String getName() { return name; }
+ public byte getKey() { return key; }
+
+ public void write(DataOutputStream s) throws IOException {
+ s.writeByte(key);
+ }
+}
diff --git a/util/testsrc/UtilModuleTests.java b/util/testsrc/UtilModuleTests.java
new file mode 100644
index 000000000..ddb1da5f5
--- /dev/null
+++ b/util/testsrc/UtilModuleTests.java
@@ -0,0 +1,30 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+// default package
+
+import junit.framework.*;
+import junit.framework.Test;
+
+public class UtilModuleTests extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(UtilModuleTests.class.getName());
+ suite.addTest(org.aspectj.util.UtilTests.suite());
+ return suite;
+ }
+
+ public UtilModuleTests(String name) { super(name); }
+
+}
diff --git a/util/testsrc/org/aspectj/util/FileUtilTest.java b/util/testsrc/org/aspectj/util/FileUtilTest.java
new file mode 100644
index 000000000..7cda1692c
--- /dev/null
+++ b/util/testsrc/org/aspectj/util/FileUtilTest.java
@@ -0,0 +1,377 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.util;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import junit.framework.TestCase;
+import junit.textui.TestRunner;
+
+/**
+ *
+ */
+public class FileUtilTest extends TestCase {
+ public static final String[] NONE = new String[0];
+
+ boolean log = false;
+
+ /** List of File files or directories to delete when exiting */
+ final ArrayList tempFiles;
+ public FileUtilTest(String s) {
+ super(s);
+ tempFiles = new ArrayList();
+ }
+
+ public static void main(String[] args) {
+ TestRunner.main(new String[] {"org.aspectj.util.FileUtilUT"});
+ }
+
+ public void tearDown() {
+ for (ListIterator iter = tempFiles.listIterator(); iter.hasNext();) {
+ File dir = (File) iter.next();
+ FileUtil.deleteContents(dir);
+ dir.delete();
+ iter.remove();
+ }
+ }
+
+ public void testDirCopySubdirs() throws IOException { // XXX dir diff
+ File srcDir = new File("src");
+ File destDir = FileUtil.getTempDir("testDirCopySubdirs");
+ FileUtil.copyDir(srcDir, destDir);
+ FileUtil.deleteContents(destDir);
+ destDir.delete();
+ }
+
+ public void testDirCopySubdirsSuffix() throws IOException { // XXX dir diff
+ File srcDir = new File("src");
+ File destDir = FileUtil.getTempDir("testDirCopySubdirsSuffix");
+ FileUtil.copyDir(srcDir, destDir, ".java", ".aj");
+
+ FileUtil.deleteContents(destDir);
+ destDir.delete();
+ }
+
+ public void testGetURL() {
+ String[] args = new String[]
+ {".", "../util/testdata", "../lib/test/aspectjrt.jar" };
+ for (int i = 0; i < args.length; i++) {
+ checkGetURL(args[i]);
+ }
+ }
+
+ /**
+ * Method checkGetURL.
+ * @param string
+ * @param uRL
+ */
+ private void checkGetURL(String arg) {
+ assertTrue(null != arg);
+ File f = new File(arg);
+ assertTrue(null != f);
+ URL url = FileUtil.getFileURL(f);
+ assertTrue(null != url);
+ log("url " + url);
+ if (!f.exists()) {
+ log("not exist " + f);
+ } else if (f.isDirectory()) {
+ log("directory " + f);
+ } else {
+ log(" file " + f);
+ InputStream in = null;
+ try {
+ in = url.openStream();
+ } catch (IOException e) {
+ assertTrue("IOException: " + e, false);
+ } finally {
+ if (null != in) {
+ try { in.close(); }
+ catch (IOException e) {}
+ }
+ }
+ }
+ }
+
+
+ public void testGetTempDir() {
+ boolean pass = true;
+ boolean delete = true;
+ checkGetTempDir("parent", null, pass, delete);
+ checkGetTempDir(null, "child", pass, delete);
+ tempFiles.add(checkGetTempDir("parent", "child", pass, !delete));
+ tempFiles.add(checkGetTempDir("parent", "child", pass, !delete));
+ tempFiles.add(checkGetTempDir("parent", "child", pass, !delete));
+ }
+
+ File checkGetTempDir(String parent, String child, boolean ok, boolean delete) {
+ File parentDir = FileUtil.getTempDir(parent);
+ assertTrue("unable to create " + parent, null != parentDir);
+ File dir = FileUtil.makeNewChildDir(parentDir, child);
+ log("parent=" + parent + " child=" + child + " -> " + dir);
+ assertTrue("dir: " + dir, ok == (dir.canWrite() && dir.isDirectory()));
+ if (delete) {
+ dir.delete();
+ }
+ return dir;
+ }
+
+ public void testRandomFileString() {
+ ArrayList results = new ArrayList();
+ for (int i = 0; i < 1000; i++) {
+ String s = FileUtil.randomFileString();
+ if (results.contains(s)) {
+ System.err.println("warning: got duplicate at iteration " + i);
+ }
+ results.add(s);
+// System.err.print(" " + s);
+// if (0 == (i % 5)) {
+// System.err.println("");
+// }
+ }
+ }
+
+ public void testNormalizedPath() {
+ File tempFile = null;
+ try {
+ tempFile = File.createTempFile("FileUtilTest", "tmp");
+ } catch (IOException e) {
+ System.err.println("aborting test - unable to create temp file");
+ }
+ File parentDir = tempFile.getParentFile();
+ String tempFilePath = FileUtil.normalizedPath(tempFile, parentDir);
+ assertEquals(tempFile.getName(), tempFilePath);
+ }
+
+ public void testFileToClassName() {
+
+ File basedir = new File("/base/dir");
+ File classFile = new File(basedir, "foo/Bar.class");
+ assertEquals("foo.Bar", FileUtil.fileToClassName(basedir, classFile));
+
+ classFile = new File(basedir, "foo\\Bar.class");
+ assertEquals("foo.Bar", FileUtil.fileToClassName(basedir, classFile));
+
+ assertEquals("Bar", FileUtil.fileToClassName(null, classFile));
+
+ classFile = new File("/home/classes/org/aspectj/lang/JoinPoint.class");
+ assertEquals("org.aspectj.lang.JoinPoint", FileUtil.fileToClassName(null, classFile));
+
+ classFile = new File("/home/classes/com/sun/tools/Javac.class");
+ assertEquals("com.sun.tools.Javac", FileUtil.fileToClassName(null, classFile));
+ }
+
+ public void testDeleteContents() {
+ File f = new File("testdata/foo");
+ f.mkdirs();
+ File g = new File(f, "bar");
+ g.mkdirs();
+ File h = new File(g, "bash");
+ h.mkdirs();
+ int d = FileUtil.deleteContents(f);
+ assertTrue(0 == d);
+ assertTrue(0 == f.list().length);
+ f.delete();
+ assertTrue(!f.exists());
+ }
+
+ public void testLineSeek() {
+ String path = "testdata/testLineSeek";
+ File file = new File(path);
+ path = file.getPath();
+ String contents = "0123456789" + LangUtil.EOL;
+ contents += contents;
+ FileUtil.writeAsString(file, contents);
+ tempFiles.add(file);
+ List sourceList = new ArrayList();
+ sourceList.add(file.getPath());
+
+ final ArrayList errors = new ArrayList();
+ final PrintStream errorSink = new PrintStream(System.err, true) {
+ public void println(String error) {
+ errors.add(error);
+ }
+ };
+ for (int i = 0; i < 10; i++) {
+ List result = FileUtil.lineSeek(""+i, sourceList, true, errorSink);
+ assertEquals(2, result.size());
+ assertEquals(path + ":1:" + i, result.get(0));
+ assertEquals(path + ":2:" + i, result.get(1));
+ if (!LangUtil.isEmpty(errors)) { // XXX prefer fast-fail?
+ assertTrue("errors: " + errors, false);
+ }
+ }
+
+ }
+ public void testLineSeekMore() {
+ final int MAX = 3; // 1..10
+ final String prefix = new File("testdata/testLineSeek").getPath();
+ // setup files 0..MAX with 2*MAX lines
+ String[] sources = new String[MAX];
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < sources.length; i++) {
+ sources[i] = new File(prefix + i).getPath();
+ sb.append("not matched");
+ sb.append(LangUtil.EOL);
+ sb.append("0123456789");
+ sb.append(LangUtil.EOL);
+ }
+ final String contents = sb.toString();
+ for (int i = 0; i < sources.length; i++) {
+ File file = new File(sources[i]);
+ FileUtil.writeAsString(file, contents);
+ tempFiles.add(file);
+ }
+ // now test
+ final ArrayList errors = new ArrayList();
+ final PrintStream errorSink = new PrintStream(System.err, true) {
+ public void println(String error) {
+ errors.add(error);
+ }
+ };
+ List sourceList = new ArrayList();
+ sourceList.addAll(Arrays.asList(sources));
+ sourceList = Collections.unmodifiableList(sourceList);
+ for (int k = 0; k < sources.length; k++) {
+ List result = FileUtil.lineSeek(""+k, sourceList, true, errorSink);
+ // number k found in every other line of every file at index k
+ Iterator iter = result.iterator();
+ for (int i = 0; i < MAX; i++) { // for each file
+ for (int j = 1; j < (MAX+1); j++) { // for every other line
+ assertTrue(iter.hasNext());
+ assertEquals(prefix + i + ":" + 2*j + ":" + k, iter.next());
+ }
+ }
+ if (!LangUtil.isEmpty(errors)) { // XXX prefer fast-fail?
+ assertTrue("errors: " + errors, false);
+ }
+ }
+ }
+
+ public void testDirCopyNoSubdirs() throws IOException {
+ String[] srcFiles = new String[] { "one.java", "two.java", "three.java"};
+ String[] destFiles = new String[] { "three.java", "four.java", "five.java" };
+ String[] allFiles = new String[]
+ { "one.java", "two.java", "three.java", "four.java", "five.java" };
+ File srcDir = makeDir("FileUtilUT_srcDir", srcFiles);
+ File destDir = makeDir("FileUtilUT_destDir", destFiles);
+ assertTrue(null != srcDir);
+ assertTrue(null != destDir);
+ assertTrue(NONE == dirContains(srcDir, srcFiles));
+ assertTrue(NONE == dirContains(destDir, destFiles));
+
+ FileUtil.copyDir(srcDir, destDir);
+ String[] resultOne = dirContains(destDir, allFiles);
+ FileUtil.copyDir(srcDir, destDir);
+ String[] resultTwo = dirContains(destDir, allFiles);
+
+ FileUtil.deleteContents(srcDir);
+ FileUtil.deleteContents(destDir);
+ srcDir.delete();
+ destDir.delete();
+
+ assertTrue(NONE == resultOne);
+ assertTrue(NONE == resultTwo);
+ }
+
+ public void testDirCopyNoSubdirsWithSuffixes() throws IOException {
+ String[] srcFiles = new String[] { "one.java", "two.java", "three.java"};
+ String[] destFiles = new String[] { "three.java", "four.java", "five.java" };
+ String[] allFiles = new String[]
+ { "one.aj", "two.aj", "three.aj", "three.java", "four.java", "five.java" };
+ File srcDir = makeDir("FileUtilUT_srcDir", srcFiles);
+ File destDir = makeDir("FileUtilUT_destDir", destFiles);
+ assertTrue(null != srcDir);
+ assertTrue(null != destDir);
+ assertTrue(NONE == dirContains(srcDir, srcFiles));
+ assertTrue(NONE == dirContains(destDir, destFiles));
+
+ FileUtil.copyDir(srcDir, destDir, ".java", ".aj");
+ String[] resultOne = dirContains(destDir, allFiles);
+ FileUtil.copyDir(srcDir, destDir, ".java", ".aj");
+ String[] resultTwo = dirContains(destDir, allFiles);
+
+ FileUtil.deleteContents(srcDir);
+ FileUtil.deleteContents(destDir);
+ srcDir.delete();
+ destDir.delete();
+
+ assertTrue(NONE == resultOne);
+ assertTrue(NONE == resultTwo);
+ }
+
+ public void testDirCopySubdirsSuffixRoundTrip() throws IOException {
+ final File srcDir = new File("src");
+ final File one = FileUtil.getTempDir("testDirCopySubdirsSuffixRoundTrip_1");
+ final File two = FileUtil.getTempDir("testDirCopySubdirsSuffixRoundTrip_2");
+ FileUtil.copyDir(srcDir, one); // no selection
+ FileUtil.copyDir(two, one, ".java", ".aj"); // only .java files
+ FileUtil.copyDir(one, two, ".aj", ".java");
+
+ FileUtil.deleteContents(one);
+ one.delete();
+ FileUtil.deleteContents(two);
+ two.delete();
+ }
+
+ /**
+ * Verify that dir contains files,
+ * and return the names of other files in dir.
+ * @return the contents of dir after excluding files
+ * or NONE if none
+ * @throws AssertionFailedError if any files are not in dir
+ */
+ String[] dirContains(File dir, final String[] files) {
+ final ArrayList toFind = new ArrayList(Arrays.asList(files));
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File d, String name) {
+ return !toFind.remove(name);
+ }
+ };
+ String[] result = dir.list(filter);
+ if (0 < toFind.size()) {
+ assertTrue(""+toFind, false);
+ }
+ return (result.length == 0 ? NONE : result);
+ }
+
+ File makeDir(String loc, String[] files) throws IOException {
+ File d = new File(loc);
+ d.mkdirs();
+ assertTrue(d.exists());
+ assertTrue(d.canWrite());
+ for (int i = 0; i < files.length; i++) {
+ File f = new File(d, files[i]);
+ assertTrue(files[i], f.createNewFile());
+ }
+ return d;
+ }
+
+ private void log(String s) {
+ if (log) {
+ System.err.println(s);
+ }
+ }
+}
diff --git a/util/testsrc/org/aspectj/util/LangUtilTest.java b/util/testsrc/org/aspectj/util/LangUtilTest.java
new file mode 100644
index 000000000..98aab88ba
--- /dev/null
+++ b/util/testsrc/org/aspectj/util/LangUtilTest.java
@@ -0,0 +1,266 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+package org.aspectj.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+public class LangUtilTest extends TestCase {
+
+ public LangUtilTest(String name) {
+ super(name);
+ }
+
+ /** @see LangUtil.extractOptions(String[], String[], int[], List) */
+ public void testExtractOptions() {
+ ArrayList extracted = new ArrayList();
+ String[] args = new String[] { "-d", "classes", "-classpath", "foo.jar", "-verbose", "Bar.java" };
+ String[] validOptions = new String[] { "-classpath", "-d", "-verbose", "-help" };
+ int[] optionArgs = new int[] { 1, 1, 0, 0 };
+ String[] result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ String resultString = "" + Arrays.asList(result);
+ String EXP = "[Bar.java]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ EXP = "[-d, classes, -classpath, foo.jar, -verbose]";
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+
+ // no input, no output
+ extracted.clear();
+ args = new String[] {};
+ result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+
+ // one input, nothing extracted
+ extracted.clear();
+ args = new String[] {"Bar.java"};
+ result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[Bar.java]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ EXP = "[]";
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+
+ // one input, extracted
+ extracted.clear();
+ args = new String[] {"-verbose"};
+ result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ EXP = "[-verbose]";
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+
+ // ------- booleans
+ validOptions = new String[] { "-help", "-verbose" };
+ optionArgs = null;
+
+ // one input, extracted
+ extracted.clear();
+ args = new String[] {"-verbose"};
+ result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ EXP = "[-verbose]";
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+
+ // one input, not extracted
+ extracted.clear();
+ args = new String[] {"Bar.java"};
+ result = LangUtil.extractOptions(args, validOptions, optionArgs, extracted);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[Bar.java]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ EXP = "[]";
+ resultString = "" + extracted;
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ }
+
+ /** @see LangUtil.extractOptions(String[], String[][]) */
+ public void testExtractOptionsArrayCollector() {
+ String[] args = new String[] { "-d", "classes", "-classpath", "foo.jar", "-verbose", "Bar.java" };
+ String[][] OPTIONS = new String[][] {
+ new String[] {"-classpath", null },
+ new String[] {"-d", null},
+ new String[] {"-verbose"},
+ new String[] { "-help" }};
+
+ String[][] options = LangUtil.copyStrings(OPTIONS);
+
+ String[] result = LangUtil.extractOptions(args, options);
+ String resultString = "" + Arrays.asList(result);
+ String EXP = "[Bar.java]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ assertTrue("-verbose".equals(options[2][0]));
+ assertTrue("foo.jar".equals(options[0][1]));
+ assertTrue("classes".equals(options[1][1]));
+ assertTrue("-classpath".equals(options[0][0]));
+ assertTrue("-d".equals(options[1][0]));
+ assertTrue(null == options[3][0]);
+
+ // get args back, no options set
+ args = new String[] { "Bar.java" };
+ options = LangUtil.copyStrings(OPTIONS);
+
+ result = LangUtil.extractOptions(args, options);
+ resultString = "" + Arrays.asList(result);
+ EXP = "[Bar.java]";
+ assertTrue(resultString + " != " + EXP, resultString.equals(EXP));
+ assertTrue(null == options[0][0]);
+ assertTrue(null == options[1][0]);
+ assertTrue(null == options[2][0]);
+ assertTrue(null == options[3][0]);
+ }
+
+ public void testOptionVariants() {
+ String[] NONE = new String[0];
+ String[] one = new String[] {"-1"};
+ String[] two = new String[] {"-2"};
+ String[] three= new String[] {"-3"};
+ String[] both = new String[] {"-1", "-2" };
+ String[] oneB = new String[] {"-1-"};
+ String[] bothB = new String[] {"-1-", "-2-" };
+ String[] onetwoB = new String[] {"-1", "-2-" };
+ String[] oneBtwo = new String[] {"-1-", "-2" };
+ String[] threeB = new String[] {"-1-", "-2-", "-3-"};
+ String[] athreeB = new String[] {"a", "-1-", "-2-", "-3-"};
+ String[] threeaB = new String[] {"-1-", "a", "-2-", "-3-"};
+
+ checkOptionVariants(NONE, new String[][] { NONE });
+ checkOptionVariants(one, new String[][] { one });
+ checkOptionVariants(both, new String[][] { both });
+ checkOptionVariants(oneB, new String[][] { NONE, one });
+ checkOptionVariants(bothB, new String[][] { NONE, one, new String[] {"-2"}, both });
+ checkOptionVariants(onetwoB, new String[][] { one, new String[] {"-1", "-2"}});
+ checkOptionVariants(oneBtwo, new String[][] { two, new String[] {"-1", "-2"}});
+ checkOptionVariants(threeB, new String[][]
+ {
+ NONE,
+ one,
+ two,
+ new String[] {"-1", "-2"},
+ three,
+ new String[] {"-1", "-3"},
+ new String[] {"-2", "-3"},
+ new String[] {"-1", "-2", "-3"}
+ });
+ checkOptionVariants(athreeB, new String[][]
+ {
+ new String[] {"a"},
+ new String[] {"a", "-1"},
+ new String[] {"a", "-2"},
+ new String[] {"a", "-1", "-2"},
+ new String[] {"a", "-3"},
+ new String[] {"a", "-1", "-3"},
+ new String[] {"a", "-2", "-3"},
+ new String[] {"a", "-1", "-2", "-3"}
+ });
+ checkOptionVariants(threeaB, new String[][]
+ {
+ new String[] {"a"},
+ new String[] {"-1", "a"},
+ new String[] {"a", "-2"},
+ new String[] {"-1", "a", "-2"},
+ new String[] {"a", "-3"},
+ new String[] {"-1", "a", "-3"},
+ new String[] {"a", "-2", "-3"},
+ new String[] {"-1", "a", "-2", "-3"}
+ });
+ }
+
+ void checkOptionVariants(String[] options, String[][] expected) {
+ String[][] result = LangUtil.optionVariants(options);
+ if (expected.length != result.length) {
+ assertTrue("exp=" + expected.length + " actual=" + result.length, false);
+ }
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(""+i,
+ "" + Arrays.asList(expected[i]),
+ "" + Arrays.asList(result[i]));
+ }
+ }
+
+ /** @see XMLWriterTest#testUnflattenList() */
+ public void testCommaSplit() {
+ checkCommaSplit("", new String[] {""});
+ checkCommaSplit("1", new String[] {"1"});
+ checkCommaSplit(" 1 2 ", new String[] {"1 2"});
+ checkCommaSplit(" 1 , 2 ", new String[] {"1", "2"});
+ checkCommaSplit("1,2,3,4", new String[] {"1", "2", "3", "4"});
+ }
+
+ void checkCommaSplit(String input, String[] expected) {
+ List actual = LangUtil.commaSplit(input);
+ String a = "" + actual;
+ String e = "" + Arrays.asList(expected);
+ assertTrue(e + "==" + a, e.equals(a));
+ }
+
+ public void testElideEndingLines() {
+ StringBuffer stackBuffer = LangUtil.stackToString(new RuntimeException(""), true);
+ LangUtil.elideEndingLines(LangUtil.StringChecker.TEST_PACKAGES, stackBuffer, 100);
+ String result = stackBuffer.toString();
+ if (-1 == result.indexOf("(... ")) {
+ // brittle - will fail under different top-level drivers
+ String m = "when running under eclipse or Ant, expecting (... in trace: ";
+ assertTrue( m + result, false);
+ }
+
+ stackBuffer = new StringBuffer("java.lang.RuntimeException: unimplemented"
+ + "\n at org.aspectj.ajdt.internal.core.builder.EclipseUnwovenClassFile.writeWovenBytes(EclipseUnwovenClassFile.java:59)"
+ + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.dump(BcelWeaver.java:271)"
+ + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.weave(BcelWeaver.java:233)"
+ + "\n at org.aspectj.bcweaver.bcel.BcelWeaver.weave(BcelWeaver.java:198)"
+ + "\n at org.aspectj.ajdt.internal.core.builder.AjBuildManager.weaveAndGenerateClassFiles(AjBuildanager.java:230)"
+ + "\n at org.aspectj.ajdt.internal.core.builder.AjBuildManager.batchBuild(AjBuildManager.java:50)"
+ + "\n at org.aspectj.ajdt.ajc.AjdtCommand.runCommand(AjdtCommand.java:42)"
+ + "\n at org.aspectj.testing.harness.bridge.CompilerRun.run(CompilerRun.java:222)"
+ + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)"
+ + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:167)"
+ + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:126)"
+ + "\n at org.aspectj.testing.run.Runner$IteratorWrapper.run(Runner.java:441)"
+ + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)"
+ + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:167)"
+ + "\n at org.aspectj.testing.run.Runner.runChild(Runner.java:126)"
+ + "\n at org.aspectj.testing.run.Runner$IteratorWrapper.run(Runner.java:441)"
+ + "\n at org.aspectj.testing.run.Runner.runPrivate(Runner.java:363)"
+ + "\n at org.aspectj.testing.run.Runner.run(Runner.java:114)"
+ + "\n at org.aspectj.testing.run.Runner.run(Runner.java:105)"
+ + "\n at org.aspectj.testing.run.Runner.runIterator(Runner.java:228)"
+ + "\n at org.aspectj.testing.drivers.Harness.run(Harness.java:254)"
+ + "\n at org.aspectj.testing.drivers.Harness.runMain(Harness.java:217)"
+ + "\n at org.aspectj.testing.drivers.Harness.main(Harness.java:99)"
+ + "\n at org.aspectj.testing.Harness.main(Harness.java:37)"
+ + "\n clip me");
+
+ LangUtil.elideEndingLines(LangUtil.StringChecker.TEST_PACKAGES, stackBuffer, 25);
+ result = stackBuffer.toString();
+ assertTrue(result, -1 != result.indexOf("(... "));
+ assertTrue(result, -1 == result.indexOf("org.aspectj.testing"));
+ }
+}
diff --git a/util/testsrc/org/aspectj/util/UtilTests.java b/util/testsrc/org/aspectj/util/UtilTests.java
new file mode 100644
index 000000000..7dc577941
--- /dev/null
+++ b/util/testsrc/org/aspectj/util/UtilTests.java
@@ -0,0 +1,32 @@
+/* *******************************************************************
+ * Copyright (c) 1999-2001 Xerox Corporation,
+ * 2002 Palo Alto Research Center, Incorporated (PARC).
+ * All rights reserved.
+ * This program and the accompanying materials are made available
+ * under the terms of the Common Public License v1.0
+ * which accompanies this distribution and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ *
+ * Contributors:
+ * Xerox/PARC initial implementation
+ * ******************************************************************/
+
+
+package org.aspectj.util;
+
+import junit.framework.*;
+
+public class UtilTests extends TestCase {
+
+ public static Test suite() {
+ TestSuite suite = new TestSuite(UtilTests.class.getName());
+ //$JUnit-BEGIN$
+ suite.addTestSuite(FileUtilTest.class);
+ suite.addTestSuite(LangUtilTest.class);
+ //$JUnit-END$
+ return suite;
+ }
+
+ public UtilTests(String name) { super(name); }
+
+}