| /* ******************************************************************* |
| * 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 Eclipse Public License v1.0 |
| * which accompanies this distribution and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Xerox/PARC initial implementation |
| * ******************************************************************/ |
| |
| package org.aspectj.ajdt.ajc; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileReader; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.StringTokenizer; |
| |
| public class ConfigParser { |
| Location location; |
| protected File relativeDirectory = null; |
| protected List<File> files = new LinkedList<File>(); |
| protected List<File> xmlfiles = new ArrayList<File>(); |
| private boolean fileParsed = false; |
| protected static String CONFIG_MSG = "build config error: "; |
| |
| public List<File> getFiles() { |
| return files; |
| } |
| |
| public List<File> getXmlFiles() { |
| return xmlfiles; |
| } |
| |
| public void parseCommandLine(String[] argsArray) throws ParseException { |
| location = new CommandLineLocation(); |
| LinkedList<Arg> args = new LinkedList<Arg>(); |
| for (int i = 0; i < argsArray.length; i++) { |
| args.add(new Arg(argsArray[i], location)); |
| } |
| String aspectjOptions = null; |
| try { |
| aspectjOptions = System.getenv("ASPECTJ_OPTS"); |
| if (aspectjOptions == null) { |
| aspectjOptions = System.getProperty("ASPECTJ_OPTS"); |
| } |
| } catch (Throwable t) { |
| aspectjOptions = null; |
| } |
| if (aspectjOptions != null) { |
| StringTokenizer st = new StringTokenizer(aspectjOptions); |
| while (st.hasMoreElements()) { |
| args.add(new Arg(st.nextToken(),location)); |
| } |
| } |
| parseArgs(args); |
| } |
| |
| public void parseConfigFile(File configFile) throws ParseException { |
| if (fileParsed == true) { |
| throw new ParseException(CONFIG_MSG + "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<Arg> args = new LinkedList<Arg>(); |
| 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 CPSourceLocation(configFile, lineNum))); |
| } |
| stream.close(); |
| } catch (IOException e) { |
| location = new CPSourceLocation(configFile, lineNum); |
| showError("error reading config file: " + e.toString()); |
| } |
| File oldRelativeDirectory = relativeDirectory; // for nested arg files; |
| relativeDirectory = configFile.getParentFile(); |
| parseArgs(args); |
| relativeDirectory = oldRelativeDirectory; |
| 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("\"")) { |
| if (s.length() == 1) { |
| return ""; |
| } else { |
| 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); |
| } |
| |
| protected void addXmlFile(File xmlFile) { |
| if (!xmlFile.isFile()) { |
| showError("XML file does not exist: " + xmlFile.getPath()); |
| } |
| xmlfiles.add(xmlFile); |
| } |
| |
| void addFileOrPattern(File sourceFile) { |
| if (sourceFile.getName().charAt(0) == '*') { |
| if (sourceFile.getName().equals("*.java")) { |
| addFiles(sourceFile.getParentFile(), new FileFilter() { |
| @Override |
| public boolean accept(File f) { |
| return f != null && f.getName().endsWith(".java"); |
| } |
| }); |
| } else if (sourceFile.getName().equals("*.aj")) { |
| addFiles(sourceFile.getParentFile(), new FileFilter() { |
| @Override |
| public boolean accept(File f) { |
| return f != null && f.getName().endsWith(".aj"); |
| } |
| }); |
| } else { |
| addFile(sourceFile); |
| } |
| } 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()); |
| } else { |
| |
| 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<Arg> args) { |
| showWarning("unrecognized option: " + arg); |
| } |
| |
| protected void showWarning(String message) { |
| if (location != null) { |
| message += " at " + location.toString(); |
| } |
| System.err.println(CONFIG_MSG + message); |
| } |
| |
| protected void showError(String message) { |
| throw new ParseException(CONFIG_MSG + message, location); |
| } |
| |
| void parseArgs(LinkedList<Arg> args) { |
| while (args.size() > 0) { |
| parseOneArg(args); |
| } |
| } |
| |
| protected Arg removeArg(LinkedList<Arg> args) { |
| if (args.size() == 0) { |
| showError("value missing"); |
| return null; |
| } else { |
| return args.removeFirst(); |
| } |
| } |
| |
| protected String removeStringArg(LinkedList<Arg> args) { |
| Arg arg = removeArg(args); |
| if (arg == null) { |
| return null; |
| } |
| return arg.getValue(); |
| } |
| |
| /** |
| * aop.xml configuration files can be passed on the command line. |
| */ |
| boolean isXml(String s) { |
| return s.endsWith(".xml"); |
| } |
| |
| 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<Arg> 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)); |
| if (v.endsWith("module-info.java")) { |
| parseOption(arg.getValue(), args); |
| } |
| } else if (isXml(v)) { |
| addXmlFile(makeFile(v)); |
| } else { |
| parseOption(arg.getValue(), args); |
| } |
| } |
| |
| protected void parseImportedConfigFile(String relativeFilePath) { |
| parseConfigFileHelper(makeFile(relativeFilePath)); |
| } |
| |
| public File makeFile(String name) { |
| if (relativeDirectory != null) { |
| return makeFile(relativeDirectory, name); |
| } else { |
| return makeFile(getCurrentDir(), name); |
| } |
| } |
| |
| private File makeFile(File dir, String name) { |
| name = name.replace('/', File.separatorChar); |
| File ret = new File(name); |
| boolean isAbsolute = ret.isAbsolute() || (ret.exists() && ret.getPath().startsWith(File.separator)); |
| if (!isAbsolute && (dir != null)) { |
| ret = new File(dir, name); |
| } |
| try { |
| ret = ret.getCanonicalFile(); |
| } catch (IOException ioEx) { |
| // proceed without canonicalization |
| // so nothing to do here |
| } |
| return ret; |
| } |
| |
| protected static class Arg { |
| private Location location; |
| private String value; |
| |
| @Override |
| public String toString() { |
| return "Arg[location="+location+" value="+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(); |
| |
| @Override |
| public abstract String toString(); |
| } |
| |
| static class CPSourceLocation extends Location { |
| private int line; |
| private File file; |
| |
| public CPSourceLocation(File file, int line) { |
| this.line = line; |
| this.file = file; |
| } |
| |
| @Override |
| public File getFile() { |
| return file; |
| } |
| |
| @Override |
| public File getDirectory() { |
| return file.getParentFile(); |
| } |
| |
| @Override |
| public int getLine() { |
| return line; |
| } |
| |
| @Override |
| public String toString() { |
| return file.getPath() + ":" + line; |
| } |
| } |
| |
| static class CommandLineLocation extends Location { |
| @Override |
| public File getFile() { |
| return new File(System.getProperty("user.dir")); |
| } |
| |
| @Override |
| public File getDirectory() { |
| return new File(System.getProperty("user.dir")); |
| } |
| |
| @Override |
| public int getLine() { |
| return -1; |
| } |
| |
| @Override |
| 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(); |
| } |
| } |
| } |