Package org.aspectj.org.eclipse.jdt.internal.compiler.batch

Source Code of org.aspectj.org.eclipse.jdt.internal.compiler.batch.Main$Logger

/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* 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:
*     IBM Corporation - initial API and implementation
*     Tom Tromey - Contribution for bug 125961
*     Tom Tromey - Contribution for bug 159641
*******************************************************************************/
package org.aspectj.org.eclipse.jdt.internal.compiler.batch;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.StringTokenizer;

import org.aspectj.org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.aspectj.org.eclipse.jdt.core.compiler.CharOperation;
import org.aspectj.org.eclipse.jdt.core.compiler.InvalidInputException;
import org.aspectj.org.eclipse.jdt.core.compiler.IProblem;
import org.aspectj.org.eclipse.jdt.internal.compiler.AbstractAnnotationProcessorManager;
import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
import org.aspectj.org.eclipse.jdt.internal.compiler.Compiler;
import org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerRequestor;
import org.aspectj.org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.aspectj.org.eclipse.jdt.internal.compiler.IProblemFactory;
import org.aspectj.org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRule;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.AccessRuleSet;
import org.aspectj.org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.aspectj.org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.aspectj.org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.GenericXMLWriter;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.HashtableOfInt;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.Messages;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
import org.aspectj.org.eclipse.jdt.internal.compiler.util.Util;

public class Main implements ProblemSeverities, SuffixConstants {
  /**
   * Resource bundle factory to share bundles for the same locale
   */
  public static class ResourceBundleFactory {
    private static HashMap Cache = new HashMap();
    public static synchronized ResourceBundle getBundle(Locale locale) {
      ResourceBundle bundle = (ResourceBundle) Cache.get(locale);
      if (bundle == null) {
        bundle = ResourceBundle.getBundle(Main.bundleName, locale);
        Cache.put(locale, bundle);
      }
      return bundle;
    }
  }

  public static class Logger {
    private static final String CLASS = "class"; //$NON-NLS-1$
    private static final String CLASS_FILE = "classfile"; //$NON-NLS-1$
    private static final String CLASSPATH = "classpath"; //$NON-NLS-1$
    private static final String CLASSPATH_FILE = "FILE"; //$NON-NLS-1$
    private static final String CLASSPATH_FOLDER = "FOLDER"; //$NON-NLS-1$
    private static final String CLASSPATH_ID = "id"; //$NON-NLS-1$
    private static final String CLASSPATH_JAR = "JAR"; //$NON-NLS-1$
    private static final String CLASSPATHS = "classpaths"; //$NON-NLS-1$
    private static final String COMMAND_LINE_ARGUMENT = "argument"; //$NON-NLS-1$
    private static final String COMMAND_LINE_ARGUMENTS = "command_line"; //$NON-NLS-1$
    private static final String COMPILER = "compiler"; //$NON-NLS-1$
    private static final String COMPILER_COPYRIGHT = "copyright"; //$NON-NLS-1$
    private static final String COMPILER_NAME = "name"; //$NON-NLS-1$
    private static final String COMPILER_VERSION = "version"; //$NON-NLS-1$
    public static final int EMACS = 2;
    private static final String ERROR = "ERROR"; //$NON-NLS-1$
    private static final String ERROR_TAG = "error"; //$NON-NLS-1$
    private static final String EXCEPTION = "exception"; //$NON-NLS-1$
    private static final String EXTRA_PROBLEM_TAG = "extra_problem"; //$NON-NLS-1$
    private static final String EXTRA_PROBLEMS = "extra_problems"; //$NON-NLS-1$
    private static final HashtableOfInt FIELD_TABLE = new HashtableOfInt();
    private static final String KEY = "key"; //$NON-NLS-1$
    private static final String MESSAGE = "message"; //$NON-NLS-1$
    private static final String NUMBER_OF_CLASSFILES = "number_of_classfiles"; //$NON-NLS-1$
    private static final String NUMBER_OF_ERRORS = "errors"; //$NON-NLS-1$
    private static final String NUMBER_OF_LINES = "number_of_lines"; //$NON-NLS-1$
    private static final String NUMBER_OF_PROBLEMS = "problems"; //$NON-NLS-1$
    private static final String NUMBER_OF_TASKS = "tasks"; //$NON-NLS-1$
    private static final String NUMBER_OF_WARNINGS = "warnings"; //$NON-NLS-1$
    private static final String OPTION = "option"; //$NON-NLS-1$
    private static final String OPTIONS = "options"; //$NON-NLS-1$
    private static final String OUTPUT = "output"; //$NON-NLS-1$
    private static final String PACKAGE = "package"; //$NON-NLS-1$
    private static final String PATH = "path"; //$NON-NLS-1$
    private static final String PROBLEM_ARGUMENT = "argument"; //$NON-NLS-1$
    private static final String PROBLEM_ARGUMENT_VALUE = "value"; //$NON-NLS-1$
    private static final String PROBLEM_ARGUMENTS = "arguments"; //$NON-NLS-1$
    private static final String PROBLEM_CATEGORY_ID = "categoryID"; //$NON-NLS-1$
    private static final String ID = "id"; //$NON-NLS-1$
    private static final String PROBLEM_ID = "problemID"; //$NON-NLS-1$
    private static final String PROBLEM_LINE = "line"; //$NON-NLS-1$
    private static final String PROBLEM_OPTION_KEY = "optionKey"; //$NON-NLS-1$
    private static final String PROBLEM_MESSAGE = "message"; //$NON-NLS-1$
    private static final String PROBLEM_SEVERITY = "severity"; //$NON-NLS-1$
    private static final String PROBLEM_SOURCE_END = "charEnd"; //$NON-NLS-1$
    private static final String PROBLEM_SOURCE_START = "charStart"; //$NON-NLS-1$
    private static final String PROBLEM_SUMMARY = "problem_summary"; //$NON-NLS-1$
    private static final String PROBLEM_TAG = "problem"; //$NON-NLS-1$
    private static final String PROBLEMS = "problems"; //$NON-NLS-1$
    private static final String SOURCE = "source"; //$NON-NLS-1$
    private static final String SOURCE_CONTEXT = "source_context"; //$NON-NLS-1$
    private static final String SOURCE_END = "sourceEnd"; //$NON-NLS-1$
    private static final String SOURCE_START = "sourceStart"; //$NON-NLS-1$
    private static final String SOURCES = "sources"; //$NON-NLS-1$
    private static final String STATS = "stats"; //$NON-NLS-1$
    private static final String TASK = "task"; //$NON-NLS-1$
    private static final String TASKS = "tasks"; //$NON-NLS-1$
    private static final String TIME = "time"; //$NON-NLS-1$
    private static final String VALUE = "value"; //$NON-NLS-1$
    private static final String WARNING = "WARNING"; //$NON-NLS-1$

    public static final int XML = 1;

    private static final String XML_DTD_DECLARATION = "<!DOCTYPE compiler PUBLIC \"-//Eclipse.org//DTD Eclipse JDT 3.2.003 Compiler//EN\" \"http://www.eclipse.org/jdt/core/compiler_32_003.dtd\">"; //$NON-NLS-1$
    static {
      try {
        Class c = IProblem.class;
        Field[] fields = c.getFields();
        for (int i = 0, max = fields.length; i < max; i++) {
          Field field = fields[i];
          if (field.getType().equals(Integer.TYPE)) {
            Integer value = (Integer) field.get(null);
            Logger.FIELD_TABLE.put(value.intValue() & IProblem.IgnoreCategoriesMask, field.getName());
          }
        }
      } catch (SecurityException e) {
        e.printStackTrace();
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    }
    private PrintWriter err;
    private PrintWriter log;
    private Main main;
    private PrintWriter out;
    private HashMap parameters;
    int tagBits;
    public Logger(Main main, PrintWriter out, PrintWriter err) {
      this.out = out;
      this.err = err;
      this.parameters = new HashMap();
      this.main = main;
    }

    public String buildFileName(
      String outputPath,
      String relativeFileName) {
      char fileSeparatorChar = File.separatorChar;
      String fileSeparator = File.separator;

      outputPath = outputPath.replace('/', fileSeparatorChar);
      // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
      StringBuffer outDir = new StringBuffer(outputPath);
      if (!outputPath.endsWith(fileSeparator)) {
        outDir.append(fileSeparator);
      }
      StringTokenizer tokenizer =
        new StringTokenizer(relativeFileName, fileSeparator);
      String token = tokenizer.nextToken();
      while (tokenizer.hasMoreTokens()) {
        outDir.append(token).append(fileSeparator);
        token = tokenizer.nextToken();
      }
      // token contains the last one
      return outDir.append(token).toString();
    }

    public void close() {
      if (this.log != null) {
        if ((this.tagBits & Logger.XML) != 0) {
          this.endTag(Logger.COMPILER);
          this.flush();
        }
        this.log.close();
      }
    }

    /**
     *
     */
    public void compiling() {
      this.printlnOut(this.main.bind("progress.compiling")); //$NON-NLS-1$
    }

    /**
     * Used to stop logging problems.
     * Only use in xml mode.
     */
    private void endLoggingProblems() {
      this.endTag(Logger.PROBLEMS);
    }
    private void endLoggingExtraProblems() {
      this.endTag(Logger.EXTRA_PROBLEMS);
    }
    public void endLoggingSource() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.endTag(Logger.SOURCE);
      }
    }

    public void endLoggingSources() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.endTag(Logger.SOURCES);
      }
    }

    public void endLoggingTasks() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.endTag(Logger.TASKS);
      }
    }
    private void endTag(String name) {
      ((GenericXMLWriter) this.log).endTag(name, true, true);
    }
    private void extractContext(CategorizedProblem problem, char[] unitSource) {
      //sanity .....
      int startPosition = problem.getSourceStart();
      int endPosition = problem.getSourceEnd();
      if (unitSource == null) {
        if (problem.getOriginatingFileName() != null) {
          try {
            unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null);
          } catch(IOException e) {
            // ignore
          }
        }
      }
      int length = unitSource== null ? 0 : unitSource.length;
      if ((startPosition > endPosition)
          || ((startPosition < 0) && (endPosition < 0))
          || (length <= 0)
          || (endPosition > length)) {
        this.parameters.put(Logger.VALUE, Messages.problem_noSourceInformation);
        this.parameters.put(Logger.SOURCE_START, "-1"); //$NON-NLS-1$
        this.parameters.put(Logger.SOURCE_END, "-1"); //$NON-NLS-1$
        this.printTag(Logger.SOURCE_CONTEXT, this.parameters, true, true);
        return;
      }

      char c;
      //the next code tries to underline the token.....
      //it assumes (for a good display) that token source does not
      //contain any \r \n. This is false on statements !
      //(the code still works but the display is not optimal !)

      // expand to line limits
      int begin, end;
      for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) {
        if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break;
      }
      for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) {
        if ((c = unitSource[end + 1]) == '\r' || c == '\n') break;
      }

      // trim left and right spaces/tabs
      while ((c = unitSource[begin]) == ' ' || c == '\t') begin++;
      while ((c = unitSource[end]) == ' ' || c == '\t') end--;

      // copy source
      StringBuffer buffer = new StringBuffer();
      buffer.append(unitSource, begin, end - begin + 1);

      this.parameters.put(Logger.VALUE, String.valueOf(buffer));
      this.parameters.put(Logger.SOURCE_START, Integer.toString(startPosition - begin));
      this.parameters.put(Logger.SOURCE_END, Integer.toString(endPosition - begin));
      this.printTag(Logger.SOURCE_CONTEXT, this.parameters, true, true);
    }

    public void flush() {
      this.out.flush();
      this.err.flush();
      if (this.log != null) {
        this.log.flush();
      }
    }
    private String getFieldName(int id) {
      return (String) Logger.FIELD_TABLE.get(id & IProblem.IgnoreCategoriesMask);
    }

    // find out an option name controlling a given problemID
    private String getProblemOptionKey(int problemID) {
      long irritant = ProblemReporter.getIrritant(problemID);
      return CompilerOptions.optionKeyFromIrritant(irritant);
    }

    public void logAverage(long[] times, long lineCount) {
      Arrays.sort(times);
      final int length = times.length;
      long sum = 0;
      for (int i = 1, max = length - 1; i < max; i++) {
        sum += times[i];
      }
      long time = sum / (length - 2);
      this.printlnOut(this.main.bind(
        "compile.averageTime", //$NON-NLS-1$
        new String[] {
          String.valueOf(lineCount),
          String.valueOf(time),
          String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0) }));
    }

    public void logClassFile(boolean generatePackagesStructure, String outputPath, String relativeFileName) {
      if ((this.tagBits & Logger.XML) != 0) {
        String fileName = null;
        if (generatePackagesStructure) {
          fileName = buildFileName(outputPath, relativeFileName);
        } else {
          char fileSeparatorChar = File.separatorChar;
          String fileSeparator = File.separator;
          // First we ensure that the outputPath exists
          outputPath = outputPath.replace('/', fileSeparatorChar);
          // To be able to pass the mkdirs() method we need to remove the extra file separator at the end of the outDir name
          int indexOfPackageSeparator = relativeFileName.lastIndexOf(fileSeparatorChar);
          if (indexOfPackageSeparator == -1) {
            if (outputPath.endsWith(fileSeparator)) {
              fileName = outputPath + relativeFileName;
            } else {
              fileName = outputPath + fileSeparator + relativeFileName;
            }
          } else {
            int length = relativeFileName.length();
            if (outputPath.endsWith(fileSeparator)) {
              fileName = outputPath + relativeFileName.substring(indexOfPackageSeparator + 1, length);
            } else {
              fileName = outputPath + fileSeparator + relativeFileName.substring(indexOfPackageSeparator + 1, length);
            }
          }
        }
        File f = new File(fileName);
        try {
          this.parameters.put(Logger.PATH, f.getCanonicalPath());
          this.printTag(Logger.CLASS_FILE, this.parameters, true, true);
        } catch (IOException e) {
          this.logNoClassFileCreated(outputPath, relativeFileName, e);
        }
      }
    }
    public void logClasspath(FileSystem.Classpath[] classpaths) {
      if (classpaths == null) return;
      if ((this.tagBits & Logger.XML) != 0) {
        final int length = classpaths.length;
        if (length != 0) {
          // generate xml output
          this.printTag(Logger.CLASSPATHS, null, true, false);
          for (int i = 0; i < length; i++) {
            String classpath = classpaths[i].getPath();
            this.parameters.put(Logger.PATH, classpath);
            File f = new File(classpath);
            String id = null;
            if (f.isFile()) {
              if (Util.isArchiveFileName(classpath)) {
                id = Logger.CLASSPATH_JAR;
              } else {
                id = Logger.CLASSPATH_FILE;
              }
            } else if (f.isDirectory()) {
              id = Logger.CLASSPATH_FOLDER;
            }
            if (id != null) {
              this.parameters.put(Logger.CLASSPATH_ID, id);
              this.printTag(Logger.CLASSPATH, this.parameters, true, true);
            }
          }
          this.endTag(Logger.CLASSPATHS);
        }
      }

    }
    public void logCommandLineArguments(String[] commandLineArguments) {
      if (commandLineArguments == null) return;
      if ((this.tagBits & Logger.XML) != 0) {
        final int length = commandLineArguments.length;
        if (length != 0) {
          // generate xml output
          this.printTag(Logger.COMMAND_LINE_ARGUMENTS, null, true, false);
          for (int i = 0; i < length; i++) {
            this.parameters.put(Logger.VALUE, commandLineArguments[i]);
            this.printTag(Logger.COMMAND_LINE_ARGUMENT, this.parameters, true, true);
          }
          this.endTag(Logger.COMMAND_LINE_ARGUMENTS);
        }
      }
    }

    /**
     * @param e the given exception to log
     */
    public void logException(Exception e) {
      StringWriter writer = new StringWriter();
      PrintWriter printWriter = new PrintWriter(writer);
      e.printStackTrace(printWriter);
      printWriter.flush();
      printWriter.close();
      final String stackTrace = writer.getBuffer().toString();
      if ((this.tagBits & Logger.XML) != 0) {
        LineNumberReader reader = new LineNumberReader(new StringReader(stackTrace));
        String line;
        int i = 0;
        StringBuffer buffer = new StringBuffer();
        String message = e.getMessage();
        if (message != null) {
          buffer.append(message).append(Util.LINE_SEPARATOR);
        }
        try {
          while ((line = reader.readLine()) != null && i < 4) {
            buffer.append(line).append(Util.LINE_SEPARATOR);
            i++;
          }
          reader.close();
        } catch (IOException e1) {
          // ignore
        }
        message = buffer.toString();
        this.parameters.put(Logger.MESSAGE, message);
        this.parameters.put(Logger.CLASS, e.getClass());
        this.printTag(Logger.EXCEPTION, this.parameters, true, true);
      }
      String message = e.getMessage();
      if (message == null) {
        this.printlnErr(stackTrace);
      } else {
        this.printlnErr(message);
      }
    }

    /**
     * @param wrongClasspath
     *            the given wrong classpath entry
     */
    public void logIncorrectClasspath(String wrongClasspath) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectClasspath", wrongClasspath)); //$NON-NLS-1$
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind(
        "configure.incorrectClasspath", wrongClasspath)); //$NON-NLS-1$
    }

    /**
     * @param wrongPath
     *            the given wrong path entry
     */
    public void logIncorrectEndorsedDirsEntry(String wrongPath) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectEndorsedDirsEntry", wrongPath)); //$NON-NLS-1$
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind(
        "configure.incorrectEndorsedDirsEntry", wrongPath)); //$NON-NLS-1$
    }

    /**
     * @param wrongPath
     *            the given wrong path entry
     */
    public void logIncorrectExtDirsEntry(String wrongPath) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectExtDirsEntry", wrongPath)); //$NON-NLS-1$
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind(
        "configure.incorrectExtDirsEntry", wrongPath)); //$NON-NLS-1$
    }

    public void logIncorrectVMVersionForAnnotationProcessing() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind("configure.incorrectVMVersionforAPT")); //$NON-NLS-1$
    }

    /**
     *
     */
    public void logNoClassFileCreated(String outputDir, String relativeFileName, IOException e) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("output.noClassFileCreated", //$NON-NLS-1$
          new String[] {
            outputDir,
            relativeFileName,
            e.getMessage()
          }));
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind("output.noClassFileCreated", //$NON-NLS-1$
        new String[] {
          outputDir,
          relativeFileName,
          e.getMessage()
        }));
    }

    public void logNoClasspath() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.noClasspath")); //$NON-NLS-1$
        this.printTag(Logger.ERROR_TAG, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind("configure.noClasspath")); //$NON-NLS-1$
    }

    /**
     * @param exportedClassFilesCounter
     */
    public void logNumberOfClassFilesGenerated(int exportedClassFilesCounter) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.VALUE, new Integer(exportedClassFilesCounter));
        this.printTag(Logger.NUMBER_OF_CLASSFILES, this.parameters, true, true);
      }
      if (exportedClassFilesCounter == 1) {
        this.printlnOut(this.main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$
      } else {
        this.printlnOut(this.main.bind("compile.severalClassFilesGenerated", //$NON-NLS-1$
          String.valueOf(exportedClassFilesCounter)));
      }
    }

    /**
     * @param options the given compiler options
     */
    public void logOptions(Map options) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.printTag(Logger.OPTIONS, null, true, false);
        final Set entriesSet = options.entrySet();
        Object[] entries = entriesSet.toArray();
        Arrays.sort(entries, new Comparator() {
          public int compare(Object o1, Object o2) {
            Map.Entry entry1 = (Map.Entry) o1;
            Map.Entry entry2 = (Map.Entry) o2;
            return ((String) entry1.getKey()).compareTo((String) entry2.getKey());
          }
        });
        for (int i = 0, max = entries.length; i < max; i++) {
          Map.Entry entry = (Map.Entry) entries[i];
          String key = (String) entry.getKey();
          this.parameters.put(Logger.KEY, key);
          this.parameters.put(Logger.VALUE, entry.getValue());
          this.printTag(Logger.OPTION, this.parameters, true, true);
        }
        this.endTag(Logger.OPTIONS);
      }
    }

    private void logProblem(CategorizedProblem problem, int localErrorCount,
      int globalErrorCount, char[] unitSource) {
      if ((this.tagBits & Logger.EMACS) != 0) {
        String result = (new String(problem.getOriginatingFileName())
            + ":" //$NON-NLS-1$
            + problem.getSourceLineNumber()
            + ": " //$NON-NLS-1$
            + (problem.isError() ? this.main.bind("output.emacs.error") : this.main.bind("output.emacs.warning")) //$NON-NLS-1$ //$NON-NLS-2$
            + ": " //$NON-NLS-1$
            + problem.getMessage());
        this.printlnErr(result);
        final String errorReportSource = errorReportSource(problem, unitSource, this.tagBits);
        if (errorReportSource.length() != 0) this.printlnErr(errorReportSource);
      } else {
        if (localErrorCount == 0) {
          this.printlnErr("----------"); //$NON-NLS-1$
        }
        this.printErr(problem.isError() ?
            this.main.bind(
                "requestor.error", //$NON-NLS-1$
                Integer.toString(globalErrorCount),
                new String(problem.getOriginatingFileName()))
                : this.main.bind(
                    "requestor.warning", //$NON-NLS-1$
                    Integer.toString(globalErrorCount),
                    new String(problem.getOriginatingFileName())));
        try {
          final String errorReportSource = errorReportSource(problem, unitSource, 0);
          this.printlnErr(errorReportSource);
          this.printlnErr(problem.getMessage());
        } catch (Exception e) {
          this.printlnErr(this.main.bind(
            "requestor.notRetrieveErrorMessage", problem.toString())); //$NON-NLS-1$
        }
        this.printlnErr("----------"); //$NON-NLS-1$
      }
    }

    public int logProblems(CategorizedProblem[] problems, char[] unitSource, Main currentMain) {
      final int count = problems.length;
      int localErrorCount = 0;
      int localProblemCount = 0;
      if (count != 0) {
        int errors = 0;
        int warnings = 0;
        int tasks = 0;
        for (int i = 0; i < count; i++) {
          CategorizedProblem problem = problems[i];
          if (problem != null) {
            currentMain.globalProblemsCount++;
            this.logProblem(problem, localProblemCount, currentMain.globalProblemsCount, unitSource);
            localProblemCount++;
            if (problem.isError()) {
              localErrorCount++;
              errors++;
              currentMain.globalErrorsCount++;
            } else if (problem.getID() == IProblem.Task) {
              currentMain.globalTasksCount++;
              tasks++;
            } else {
              currentMain.globalWarningsCount++;
              warnings++;
            }
          }
        }
        if ((this.tagBits & Logger.XML) != 0) {
          if ((errors + warnings) != 0) {
            this.startLoggingProblems(errors, warnings);
            for (int i = 0; i < count; i++) {
              CategorizedProblem problem = problems[i];
              if (problem!= null) {
                if (problem.getID() != IProblem.Task) {
                  this.logXmlProblem(problem, unitSource);
                }
              }
            }
            this.endLoggingProblems();
          }
          if (tasks != 0) {
            this.startLoggingTasks(tasks);
            for (int i = 0; i < count; i++) {
              CategorizedProblem problem = problems[i];
              if (problem!= null) {
                if (problem.getID() == IProblem.Task) {
                  this.logXmlTask(problem, unitSource);
                }
              }
            }
            this.endLoggingTasks();
          }
        }
      }
      return localErrorCount;
    }

    /**
     * @param globalProblemsCount
     * @param globalErrorsCount
     * @param globalWarningsCount
     */
    public void logProblemsSummary(int globalProblemsCount,
      int globalErrorsCount, int globalWarningsCount, int globalTasksCount) {
      if ((this.tagBits & Logger.XML) != 0) {
        // generate xml
        this.parameters.put(Logger.NUMBER_OF_PROBLEMS, new Integer(globalProblemsCount));
        this.parameters.put(Logger.NUMBER_OF_ERRORS, new Integer(globalErrorsCount));
        this.parameters.put(Logger.NUMBER_OF_WARNINGS, new Integer(globalWarningsCount));
        this.parameters.put(Logger.NUMBER_OF_TASKS, new Integer(globalTasksCount));
        this.printTag(Logger.PROBLEM_SUMMARY, this.parameters, true, true);
      }
      if (globalProblemsCount == 1) {
        String message = null;
        if (globalErrorsCount == 1) {
          message = this.main.bind("compile.oneError"); //$NON-NLS-1$
        } else {
          message = this.main.bind("compile.oneWarning"); //$NON-NLS-1$
        }
        this.printErr(this.main.bind("compile.oneProblem", message)); //$NON-NLS-1$
      } else {
        String errorMessage = null;
        String warningMessage = null;
        if (globalErrorsCount > 0) {
          if (globalErrorsCount == 1) {
            errorMessage = this.main.bind("compile.oneError"); //$NON-NLS-1$
          } else {
            errorMessage = this.main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)); //$NON-NLS-1$
          }
        }
        int warningsNumber = globalWarningsCount + globalTasksCount;
        if (warningsNumber > 0) {
          if (warningsNumber == 1) {
            warningMessage = this.main.bind("compile.oneWarning"); //$NON-NLS-1$
          } else {
            warningMessage = this.main.bind("compile.severalWarnings", String.valueOf(warningsNumber)); //$NON-NLS-1$
          }
        }
        if (errorMessage == null || warningMessage == null) {
          if (errorMessage == null) {
            this.printErr(this.main.bind(
              "compile.severalProblemsErrorsOrWarnings", //$NON-NLS-1$
              String.valueOf(globalProblemsCount),
              warningMessage));
          } else {
            this.printErr(this.main.bind(
              "compile.severalProblemsErrorsOrWarnings", //$NON-NLS-1$
              String.valueOf(globalProblemsCount),
              errorMessage));
          }
        } else {
          this.printErr(this.main.bind(
            "compile.severalProblemsErrorsAndWarnings", //$NON-NLS-1$
            new String[] {
              String.valueOf(globalProblemsCount),
              errorMessage,
              warningMessage
            }));
        }
      }
      if ((this.tagBits & Logger.EMACS) != 0) {
        this.printlnErr();
      }
    }

    /**
     *
     */
    public void logProgress() {
      this.printOut('.');
    }

    /**
     * @param i
     *            the current repetition number
     * @param repetitions
     *            the given number of repetitions
     */
    public void logRepetition(int i, int repetitions) {
      this.printlnOut(this.main.bind("compile.repetition", //$NON-NLS-1$
        String.valueOf(i + 1), String.valueOf(repetitions)));
    }

    /**
     * @param time
     * @param lineCount
     */
    public void logTiming(long time, long lineCount) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.VALUE, new Long(time));
        this.printTag(Logger.TIME, this.parameters, true, true);
        this.parameters.put(Logger.VALUE, new Long(lineCount));
        this.printTag(Logger.NUMBER_OF_LINES, this.parameters, true, true);
      }
      if (lineCount != 0) {
        this.printlnOut(this.main.bind(
          "compile.instantTime", //$NON-NLS-1$
          new String[] {
            String.valueOf(lineCount),
            String.valueOf(time),
            String.valueOf(((int) (lineCount * 10000.0 / time)) / 10.0) }));
      } else {
        this.printlnOut(this.main.bind("compile.totalTime", String.valueOf(time))); //$NON-NLS-1$
      }
    }

    /**
     * Print the usage of the compiler
     * @param usage
     */
    public void logUsage(String usage) {
      this.printlnOut(usage);
    }

    /**
     * Print the version of the compiler in the log and/or the out field
     */
    public void logVersion(final boolean printToOut) {
      // New AspectJ Extension
      // old code:
      /*
      if (this.log != null && (this.tagBits & Logger.XML) == 0) {
        final String version = this.main.bind("misc.version", //$NON-NLS-1$
          new String[] {
            this.main.bind("compiler.name"), //$NON-NLS-1$
            this.main.bind("compiler.version"), //$NON-NLS-1$
            this.main.bind("compiler.copyright") //$NON-NLS-1$
          }
        );
        this.log.println("# " + version); //$NON-NLS-1$
        if (printToOut) {
          this.out.println(version);
          this.out.flush();
        }
      } else if (printToOut) {
        final String version = this.main.bind("misc.version", //$NON-NLS-1$
          new String[] {
            this.main.bind("compiler.name"), //$NON-NLS-1$
            this.main.bind("compiler.version"), //$NON-NLS-1$
            this.main.bind("compiler.copyright") //$NON-NLS-1$
          }
        );
        this.out.println(version);
        this.out.flush();
      }
      */
      // new code:
      if (printToOut)   this.main.printVersion();
      // End AspectJ Extension
    }
    /**
     * Print the usage of wrong JDK
     */
    public void logWrongJDK() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.MESSAGE, this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$
        this.printTag(Logger.ERROR, this.parameters, true, true);
      }
      this.printlnErr(this.main.bind("configure.requiresJDK1.2orAbove")); //$NON-NLS-1$
    }

    /**
     * @param problem
     *            the given problem to log
     * @param unitSource
     *            the given unit source
     */
    private void logXmlProblem(CategorizedProblem problem, char[] unitSource) {
      final int sourceStart = problem.getSourceStart();
      final int sourceEnd = problem.getSourceEnd();
      final int id = problem.getID();
      this.parameters.put(Logger.ID, getFieldName(id)); // ID as field name
      this.parameters.put(Logger.PROBLEM_ID, new Integer(id)); // ID as numeric value
      boolean isError = problem.isError();
      int severity = isError ? ProblemSeverities.Error : ProblemSeverities.Warning;
      this.parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : Logger.WARNING);
      this.parameters.put(Logger.PROBLEM_LINE, new Integer(problem.getSourceLineNumber()));
      this.parameters.put(Logger.PROBLEM_SOURCE_START, new Integer(sourceStart));
      this.parameters.put(Logger.PROBLEM_SOURCE_END, new Integer(sourceEnd));
      String problemOptionKey = getProblemOptionKey(id);
      if (problemOptionKey != null) {
        this.parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey);
      }
      int categoryID = ProblemReporter.getProblemCategory(severity, id);
      this.parameters.put(Logger.PROBLEM_CATEGORY_ID, new Integer(categoryID));
      this.printTag(Logger.PROBLEM_TAG, this.parameters, true, false);
      this.parameters.put(Logger.VALUE, problem.getMessage());
      this.printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
      extractContext(problem, unitSource);
      String[] arguments = problem.getArguments();
      final int length = arguments.length;
      if (length != 0) {
        this.printTag(Logger.PROBLEM_ARGUMENTS, null, true, false);
        for (int i = 0; i < length; i++) {
          this.parameters.put(Logger.PROBLEM_ARGUMENT_VALUE, arguments[i]);
          this.printTag(Logger.PROBLEM_ARGUMENT, this.parameters, true, true);
        }
        this.endTag(Logger.PROBLEM_ARGUMENTS);
      }
      this.endTag(Logger.PROBLEM_TAG);
    }

    /**
     * @param problem
     *            the given problem to log
     * @param unitSource
     *            the given unit source
     */
    private void logXmlTask(CategorizedProblem problem, char[] unitSource) {
      this.parameters.put(Logger.PROBLEM_LINE, new Integer(problem.getSourceLineNumber()));
      this.parameters.put(Logger.PROBLEM_SOURCE_START, new Integer(problem.getSourceStart()));
      this.parameters.put(Logger.PROBLEM_SOURCE_END, new Integer(problem.getSourceEnd()));
      String problemOptionKey = getProblemOptionKey(problem.getID());
      if (problemOptionKey != null) {
        this.parameters.put(Logger.PROBLEM_OPTION_KEY, problemOptionKey);
      }
      this.printTag(Logger.TASK, this.parameters, true, false);
      this.parameters.put(Logger.VALUE, problem.getMessage());
      this.printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
      extractContext(problem, unitSource);
      this.endTag(Logger.TASK);
    }

    private void printErr(String s) {
      this.err.print(s);
      if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
        this.log.print(s);
      }
    }

    private void printlnErr() {
      this.err.println();
      if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
        this.log.println();
      }
    }
    private void printlnErr(String s) {
      this.err.println(s);
      if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
        this.log.println(s);
      }
    }
    private void printlnOut(String s) {
      this.out.println(s);
      if ((this.tagBits & Logger.XML) == 0 && this.log != null) {
        this.log.println(s);
      }
    }

    /**
     *
     */
    public void printNewLine() {
      this.out.println();
    }

    private void printOut(char c) {
      this.out.print(c);
    }

    public void printStats() {
      final boolean isTimed = this.main.timing;
      if ((this.tagBits & Logger.XML) != 0) {
        this.printTag(Logger.STATS, null, true, false);
      }
      if (isTimed) {
        long time = System.currentTimeMillis() - this.main.startTime;
        this.logTiming(time, this.main.lineCount);
        if (this.main.times != null) {
          this.main.times[this.main.timesCounter++] = time;
        }
      }
      if (this.main.globalProblemsCount > 0) {
        this.logProblemsSummary(this.main.globalProblemsCount, this.main.globalErrorsCount, this.main.globalWarningsCount, main.globalTasksCount);
      }
      if (this.main.exportedClassFilesCounter != 0
          && (this.main.showProgress || isTimed || this.main.verbose)) {
        this.logNumberOfClassFilesGenerated(this.main.exportedClassFilesCounter);
      }
      if ((this.tagBits & Logger.XML) != 0) {
        this.endTag(Logger.STATS);
      }
    }

    private void printTag(String name, HashMap params, boolean insertNewLine, boolean closeTag) {
      ((GenericXMLWriter) this.log).printTag(name, parameters, true, insertNewLine, closeTag);
      this.parameters.clear();
    }

    public void setEmacs() {
      this.tagBits |= Logger.EMACS;
    }

    public void setLog(String logFileName) throws InvalidInputException {
      final Date date = new Date();
      final DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, Locale.getDefault());
      try {
        int index = logFileName.lastIndexOf('.');
        if (index != -1) {
          if (logFileName.substring(index).toLowerCase().equals(".xml")) { //$NON-NLS-1$
            this.log = new GenericXMLWriter(new FileOutputStream(logFileName, false), Util.LINE_SEPARATOR, true);
            this.tagBits |= Logger.XML;
            // insert time stamp as comment
            try {
              this.log.println("<!-- " + new String(dateFormat.format(date).getBytes(), "UTF-8") + " -->");//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
            } catch (UnsupportedEncodingException e) {
              e.printStackTrace();
            }
            this.log.println(Logger.XML_DTD_DECLARATION);
            this.parameters.put(Logger.COMPILER_NAME, this.main.bind("compiler.name")); //$NON-NLS-1$
            this.parameters.put(Logger.COMPILER_VERSION, this.main.bind("compiler.version")); //$NON-NLS-1$
            this.parameters.put(Logger.COMPILER_COPYRIGHT, this.main.bind("compiler.copyright")); //$NON-NLS-1$
            this.printTag(Logger.COMPILER, this.parameters, true, false);
          } else {
            this.log = new PrintWriter(new FileOutputStream(logFileName, false));
            this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$
          }
        } else {
          this.log = new PrintWriter(new FileOutputStream(logFileName, false));
          this.log.println("# " + dateFormat.format(date));//$NON-NLS-1$
        }
      } catch (FileNotFoundException e) {
        throw new InvalidInputException(this.main.bind("configure.cannotOpenLog", logFileName)); //$NON-NLS-1$
      }
    }

    /**
     * Used to start logging problems.
     * Only use in xml mode.
     */
    private void startLoggingProblems(int errors, int warnings) {
      this.parameters.put(Logger.NUMBER_OF_PROBLEMS, new Integer(errors + warnings));
      this.parameters.put(Logger.NUMBER_OF_ERRORS, new Integer(errors));
      this.parameters.put(Logger.NUMBER_OF_WARNINGS, new Integer(warnings));
      this.printTag(Logger.PROBLEMS, this.parameters, true, false);
    }
   
    private void startLoggingExtraProblems(int count) {
      this.parameters.put(Logger.NUMBER_OF_PROBLEMS, new Integer(count));
      this.printTag(Logger.EXTRA_PROBLEMS, this.parameters, true, false);
    }

    public void startLoggingSource(CompilationResult compilationResult) {
      if ((this.tagBits & Logger.XML) != 0) {
        ICompilationUnit compilationUnit = compilationResult.compilationUnit;
        if (compilationUnit != null) {
            char[] fileName = compilationUnit.getFileName();
            File f = new File(new String(fileName));
            if (fileName != null) {
              this.parameters.put(Logger.PATH, f.getAbsolutePath());
            }
            char[][] packageName = compilationResult.packageName;
            if (packageName != null) {
              this.parameters.put(
                  Logger.PACKAGE,
                  new String(CharOperation.concatWith(packageName, File.separatorChar)));
            }
            CompilationUnit unit = (CompilationUnit) compilationUnit;
            String destinationPath = unit.destinationPath;
          if (destinationPath == null) {
            destinationPath = this.main.destinationPath;
          }
          if (destinationPath != null && destinationPath != NONE) {
            if (File.separatorChar == '/') {
              this.parameters.put(Logger.OUTPUT, destinationPath);
            } else {
              this.parameters.put(Logger.OUTPUT, destinationPath.replace('/', File.separatorChar));
            }
          }
        }
        this.printTag(Logger.SOURCE, this.parameters, true, false);
      }
    }
    public void startLoggingSources() {
      if ((this.tagBits & Logger.XML) != 0) {
        this.printTag(Logger.SOURCES, null, true, false);
      }
    }
    public void startLoggingTasks(int tasks) {
      if ((this.tagBits & Logger.XML) != 0) {
        this.parameters.put(Logger.NUMBER_OF_TASKS, new Integer(tasks));
        this.printTag(Logger.TASKS, this.parameters, true, false);
      }
    }

    public void loggingExtraProblems(Main currentMain) {
      ArrayList problems = currentMain.extraProblems;
      final int count = problems.size();
      int localErrorCount = 0;
      int localProblemCount = 0;
      if (count != 0) {
        int errors = 0;
        int warnings = 0;
        for (int i = 0; i < count; i++) {
          CategorizedProblem problem = (CategorizedProblem) problems.get(i);
          if (problem != null) {
            currentMain.globalProblemsCount++;
            this.logExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
            localProblemCount++;
            if (problem.isError()) {
              localErrorCount++;
              errors++;
              currentMain.globalErrorsCount++;
            } else if (problem.isWarning()) {
              currentMain.globalWarningsCount++;
              warnings++;
            }
          }
        }
        if ((this.tagBits & Logger.XML) != 0) {
          if ((errors + warnings) != 0) {
            this.startLoggingExtraProblems(count);
            for (int i = 0; i < count; i++) {
              CategorizedProblem problem = (CategorizedProblem) problems.get(i);
              if (problem!= null) {
                if (problem.getID() != IProblem.Task) {
                  this.logXmlExtraProblem(problem, localProblemCount, currentMain.globalProblemsCount);
                }
              }
            }
            this.endLoggingExtraProblems();
          }
        }
      }
    }

    private void logXmlExtraProblem(CategorizedProblem problem, int globalErrorCount, int localErrorCount) {
      final int sourceStart = problem.getSourceStart();
      final int sourceEnd = problem.getSourceEnd();
      boolean isError = problem.isError();
      this.parameters.put(Logger.PROBLEM_SEVERITY, isError ? Logger.ERROR : Logger.WARNING);
      this.parameters.put(Logger.PROBLEM_LINE, new Integer(problem.getSourceLineNumber()));
      this.parameters.put(Logger.PROBLEM_SOURCE_START, new Integer(sourceStart));
      this.parameters.put(Logger.PROBLEM_SOURCE_END, new Integer(sourceEnd));
      this.printTag(Logger.EXTRA_PROBLEM_TAG, this.parameters, true, false);
      this.parameters.put(Logger.VALUE, problem.getMessage());
      this.printTag(Logger.PROBLEM_MESSAGE, this.parameters, true, true);
      extractContext(problem, null);
      this.endTag(Logger.EXTRA_PROBLEM_TAG);
    }

    private void logExtraProblem(CategorizedProblem problem, int localErrorCount, int globalErrorCount) {
      char[] originatingFileName = problem.getOriginatingFileName();
      String fileName =
        originatingFileName == null
        ? this.main.bind("requestor.noFileNameSpecified")//$NON-NLS-1$
        : new String(originatingFileName);
      if ((this.tagBits & Logger.EMACS) != 0) {
        String result = fileName
            + ":" //$NON-NLS-1$
            + problem.getSourceLineNumber()
            + ": " //$NON-NLS-1$
            + (problem.isError() ? this.main.bind("output.emacs.error") : this.main.bind("output.emacs.warning")) //$NON-NLS-1$ //$NON-NLS-2$
            + ": " //$NON-NLS-1$
            + problem.getMessage();
        this.printlnErr(result);
        final String errorReportSource = errorReportSource(problem, null, this.tagBits);
        this.printlnErr(errorReportSource);
      } else {
        if (localErrorCount == 0) {
          this.printlnErr("----------"); //$NON-NLS-1$
        }
        this.printErr(problem.isError() ?
            this.main.bind(
                "requestor.error", //$NON-NLS-1$
                Integer.toString(globalErrorCount),
                new String(fileName))
                : this.main.bind(
                    "requestor.warning", //$NON-NLS-1$
                    Integer.toString(globalErrorCount),
                    new String(fileName)));
        final String errorReportSource = errorReportSource(problem, null, 0);
        this.printlnErr(errorReportSource);
        this.printlnErr(problem.getMessage());
        this.printlnErr("----------"); //$NON-NLS-1$
      }
    }

    private String errorReportSource(CategorizedProblem problem, char[] unitSource, int bits) {
      //extra from the source the innacurate     token
      //and "highlight" it using some underneath ^^^^^
      //put some context around too.

      //this code assumes that the font used in the console is fixed size

      //sanity .....
      int startPosition = problem.getSourceStart();
      int endPosition = problem.getSourceEnd();
      if (unitSource == null) {
        if (problem.getOriginatingFileName() != null) {
          try {
            unitSource = Util.getFileCharContent(new File(new String(problem.getOriginatingFileName())), null);
          } catch (IOException e) {
            // ignore;
          }
        }
      }
      int length = unitSource == null ? 0 : unitSource.length;
      if ((startPosition > endPosition)
        || ((startPosition < 0) && (endPosition < 0))
        || length == 0)
        return Messages.problem_noSourceInformation;

      StringBuffer errorBuffer = new StringBuffer();
      if ((bits & Main.Logger.EMACS) == 0) {
        errorBuffer.append(' ').append(Messages.bind(Messages.problem_atLine, String.valueOf(problem.getSourceLineNumber())));
        errorBuffer.append(Util.LINE_SEPARATOR);
      }
      errorBuffer.append('\t');
     
      char c;
      final char SPACE = '\u0020';
      final char MARK = '^';
      final char TAB = '\t';
      //the next code tries to underline the token.....
      //it assumes (for a good display) that token source does not
      //contain any \r \n. This is false on statements !
      //(the code still works but the display is not optimal !)

      // expand to line limits
      int begin;
      int end;
      for (begin = startPosition >= length ? length - 1 : startPosition; begin > 0; begin--) {
        if ((c = unitSource[begin - 1]) == '\n' || c == '\r') break;
      }
      for (end = endPosition >= length ? length - 1 : endPosition ; end+1 < length; end++) {
        if ((c = unitSource[end + 1]) == '\r' || c == '\n') break;
      }
     
      // trim left and right spaces/tabs
      while ((c = unitSource[begin]) == ' ' || c == '\t') begin++;
      //while ((c = unitSource[end]) == ' ' || c == '\t') end--; TODO (philippe) should also trim right, but all tests are to be updated
     
      // copy source
      errorBuffer.append(unitSource, begin, end-begin+1);
      errorBuffer.append(Util.LINE_SEPARATOR).append("\t"); //$NON-NLS-1$

      // compute underline
      for (int i = begin; i <startPosition; i++) {
        errorBuffer.append((unitSource[i] == TAB) ? TAB : SPACE);
      }
      for (int i = startPosition; i <= (endPosition >= length ? length - 1 : endPosition); i++) {
        errorBuffer.append(MARK);
      }
      return errorBuffer.toString();
    }
  }
  public static String bundleName = "org.aspectj.org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$ // AspectJ Extension - made non-final

  // two uses: recognize 'none' in options; code the singleton none
  // for the '-d none' option (wherever it may be found)
  public static final int DEFAULT_SIZE_CLASSPATH = 4;
  public static final String NONE = "none"; //$NON-NLS-1$

  /*
   * Internal IDE API
   */
  public static boolean compile(String commandLine) {

    return compile(commandLine, new PrintWriter(System.out), new PrintWriter(System.err));
  }
 
   // New AspectJ Extension
   public void printVersion() {
  }
   // End AspectJ Extension
    /*
   * Internal IDE API for test harness purpose
   */
  public static boolean compile(String commandLine, PrintWriter outWriter, PrintWriter errWriter) {

    return new Main(outWriter, errWriter, false).compile(tokenize(commandLine));
  }
  public static File[][] getLibrariesFiles(File[] files) {
    FilenameFilter filter = new FilenameFilter() {
      public boolean accept(File dir, String name) {
        String lowerCaseName = name.toLowerCase();
        if (lowerCaseName.endsWith(SuffixConstants.SUFFIX_STRING_jar) || lowerCaseName.endsWith(SuffixConstants.SUFFIX_STRING_zip)) {
          return true;
        }
        return false;
      }
    };
    final int filesLength = files.length;
    File[][] result = new File[filesLength][];
    for (int i = 0; i < filesLength; i++) {
      File currentFile = files[i];
      if (currentFile.exists() && currentFile.isDirectory()) {
        result[i] = currentFile.listFiles(filter);
      }
    }
    return result;
  }
  public static void main(String[] argv) {
    new Main(new PrintWriter(System.out), new PrintWriter(System.err), true).compile(argv);
  }
  public static String[] tokenize(String commandLine) {

    int count = 0;
    String[] arguments = new String[10];
    StringTokenizer tokenizer = new StringTokenizer(commandLine, " \"", true); //$NON-NLS-1$
    String token = Util.EMPTY_STRING;
    boolean insideQuotes = false;
    boolean startNewToken = true;

    // take care to quotes on the command line
    // 'xxx "aaa bbb";ccc yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
    // 'xxx "aaa bbb;ccc" yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
    // 'xxx "aaa bbb";"ccc" yyy' --->  {"xxx", "aaa bbb;ccc", "yyy" }
    // 'xxx/"aaa bbb";"ccc" yyy' --->  {"xxx/aaa bbb;ccc", "yyy" }
    while (tokenizer.hasMoreTokens()) {
      token = tokenizer.nextToken();

      if (token.equals(" ")) { //$NON-NLS-1$
        if (insideQuotes) {
          arguments[count - 1] += token;
          startNewToken = false;
        } else {
          startNewToken = true;
        }
      } else if (token.equals("\"")) { //$NON-NLS-1$
        if (!insideQuotes && startNewToken) {
          if (count == arguments.length)
            System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
          arguments[count++] = Util.EMPTY_STRING;
        }
        insideQuotes = !insideQuotes;
        startNewToken = false;
      } else {
        if (insideQuotes) {
          arguments[count - 1] += token;
        } else {
          if (token.length() > 0 && !startNewToken) {
            arguments[count - 1] += token;
          } else {
            if (count == arguments.length)
              System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
            String trimmedToken = token.trim();
            if (trimmedToken.length() != 0) {
              arguments[count++] = trimmedToken;
            }
          }
        }
        startNewToken = false;
      }
    }
    System.arraycopy(arguments, 0, arguments = new String[count], 0, count);
    return arguments;
  }
  public Compiler batchCompiler;
  /* Bundle containing messages */
  public ResourceBundle bundle;
  protected FileSystem.Classpath[] checkedClasspaths;
  public Locale compilerLocale;
  public CompilerOptions compilerOptions; // read-only
  public String destinationPath;
  public String[] destinationPaths;
  // destination path for compilation units that get no more specific
  // one (through directory arguments or various classpath options);
  // coding is:
  // == null: unspecified, write class files close to their respective
  //          source files;
  // == Main.NONE: absorbent element, do not output class files;
  // else: use as the path of the directory into which class files must
  //       be written.
  private boolean didSpecifySource;
  private boolean didSpecifyTarget;

  public String[] encodings;

  public int exportedClassFilesCounter;
  public String[] filenames;

  public String[] classNames;

  // overrides of destinationPath on a directory argument basis
  public int globalErrorsCount;
  public int globalProblemsCount;
  public int globalTasksCount;
  public int globalWarningsCount;
  private File javaHomeCache;
  private boolean javaHomeChecked = false;
  public long lineCount;
  public String log;
  public Logger logger;
  public int maxProblems;
  public boolean noWarn = false;
  public Map options;
  protected PrintWriter out;
  public boolean proceed = true;
  public boolean proceedOnError = false;
  public boolean produceRefInfo = false;
  public int repetitions;

  public boolean showProgress = false;
  public long startTime;

public boolean systemExitWhenFinished = true;

public long[] times;

public int timesCounter;

public boolean timing = false;

public boolean verbose = false;

private String[] expandedCommandLine;

private PrintWriter err;

ArrayList extraProblems;

public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished) {
  this(outWriter, errWriter, systemExitWhenFinished, null);
}

public Main(PrintWriter outWriter, PrintWriter errWriter, boolean systemExitWhenFinished, Map customDefaultOptions) {
  this.initialize(outWriter, errWriter, systemExitWhenFinished, customDefaultOptions);
  this.relocalize();
}
public void addExtraProblems(CategorizedProblem problem) {
  if (this.extraProblems == null) {
    this.extraProblems = new ArrayList();
  }
  this.extraProblems.add(problem);
}
protected void addNewEntry(ArrayList paths, String currentClasspathName,
    ArrayList currentRuleSpecs, String customEncoding,
    String destPath, boolean isSourceOnly,
    boolean rejectDestinationPathOnJars) throws InvalidInputException {

  int rulesSpecsSize = currentRuleSpecs.size();
  AccessRuleSet accessRuleSet = null;
  if (rulesSpecsSize != 0) {
    AccessRule[] accessRules = new AccessRule[currentRuleSpecs.size()];
    boolean rulesOK = true;
    Iterator i = currentRuleSpecs.iterator();
    int j = 0;
    while (i.hasNext()) {
      String ruleSpec = (String) i.next();
      char key = ruleSpec.charAt(0);
      String pattern = ruleSpec.substring(1);
      if (pattern.length() > 0) {
        switch (key) {
          case '+':
            accessRules[j++] = new AccessRule(pattern
                .toCharArray(), 0);
            break;
          case '~':
            accessRules[j++] = new AccessRule(pattern
                .toCharArray(),
                IProblem.DiscouragedReference);
            break;
          case '-':
            accessRules[j++] = new AccessRule(pattern
                .toCharArray(),
                IProblem.ForbiddenReference);
            break;
          case '?':
            accessRules[j++] = new AccessRule(pattern
                .toCharArray(),
                IProblem.ForbiddenReference, true/*keep looking for accessible type*/);
            break;
          default:
            rulesOK = false;
        }
      } else {
        rulesOK = false;
      }
    }
    if (rulesOK) {
      String templates[] = new String[AccessRuleSet.MESSAGE_TEMPLATES_LENGTH];
      templates[0] = this.bind(
          "template.restrictedAccess.type", //$NON-NLS-1$
          new String[] {"{0}", currentClasspathName}); //$NON-NLS-1$
      templates[1] = this.bind(
          "template.restrictedAccess.constructor", //$NON-NLS-1$
          new String[] {"{0}", currentClasspathName}); //$NON-NLS-1$
      templates[2] = this.bind(
          "template.restrictedAccess.method", //$NON-NLS-1$
          new String[] {"{0}", "{1}", currentClasspathName}); //$NON-NLS-1$ //$NON-NLS-2$
      templates[3] = this.bind(
          "template.restrictedAccess.field", //$NON-NLS-1$
          new String[] {"{0}", "{1}", currentClasspathName}); //$NON-NLS-1$ //$NON-NLS-2$
      accessRuleSet = new AccessRuleSet(accessRules, templates);
    } else {
      if (currentClasspathName.length() != 0) {
        // we go on anyway
        this.logger.logIncorrectClasspath(currentClasspathName);
      }
      return;
    }
  }
  if (NONE.equals(destPath)) {
    destPath = NONE; // keep == comparison valid
  }
  if (rejectDestinationPathOnJars && destPath != null &&
      (currentClasspathName.endsWith(".jar") || //$NON-NLS-1$
        currentClasspathName.endsWith(".zip"))) { //$NON-NLS-1$
    throw new InvalidInputException(
      this.bind("configure.unexpectedDestinationPathEntryFile", //$NON-NLS-1$
            currentClasspathName));
  }
  FileSystem.Classpath currentClasspath = FileSystem.getClasspath(
      currentClasspathName,
      customEncoding,
      isSourceOnly,
      accessRuleSet,
      destPath);
  if (currentClasspath != null) {
    paths.add(currentClasspath);
  } else if (currentClasspathName.length() != 0) {
    // we go on anyway
    this.logger.logIncorrectClasspath(currentClasspathName);
  }
}
/*
* Lookup the message with the given ID in this catalog
*/
public String bind(String id) {
  return bind(id, (String[]) null);
}
/*
* Lookup the message with the given ID in this catalog and bind its
* substitution locations with the given string.
*/
public String bind(String id, String binding) {
  return bind(id, new String[] { binding });
}

/*
* Lookup the message with the given ID in this catalog and bind its
* substitution locations with the given strings.
*/
public String bind(String id, String binding1, String binding2) {
  return bind(id, new String[] { binding1, binding2 });
}

/*
* Lookup the message with the given ID in this catalog and bind its
* substitution locations with the given string values.
*/
public String bind(String id, String[] arguments) {
  if (id == null)
    return "No message available"; //$NON-NLS-1$
  String message = null;
  try {
    message = this.bundle.getString(id);
  } catch (MissingResourceException e) {
    // If we got an exception looking for the message, fail gracefully by just returning
    // the id we were looking for.  In most cases this is semi-informative so is not too bad.
    return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$
  }
  return MessageFormat.format(message, arguments);
}

//AspectJ Extension - static form of bind that just uses the default locale
public static String _bind(String id,String []arguments) {
  if (id==null) return "No message available"; //$NON-NLS-1$
  String message = null;
  try {
    message = ResourceBundleFactory.getBundle(Locale.getDefault()).getString(id);
  } catch (MissingResourceException mre) {
    // If we got an exception looking for the message, fail gracefully by just returning
    // the id we were looking for.  In most cases this is semi-informative so is not too bad.
    return "Missing message: " + id + " in: " + Main.bundleName; //$NON-NLS-2$ //$NON-NLS-1$
  }
  return MessageFormat.format(message, arguments);
}
//End AspectJ Extension
/**
* Return true if and only if the running VM supports the given minimal version.
*
* <p>This only checks the major version, since the minor version is always 0 (at least for the useful cases).</p>
* <p>The given minimalSupportedVersion is one of the constants:</p>
* <ul>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_1</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_2</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_3</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_4</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_5</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_6</code></li>
* <li><code>org.aspectj.org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants.JDK1_7</code></li>
* </ul>
* @param minimalSupportedVersion the given minimal version
* @return true if and only if the running VM supports the given minimal version, false otherwise
*/
private boolean checkVMVersion(long minimalSupportedVersion) {
  // the format of this property is supposed to be xx.x where x are digits.
  String classFileVersion = System.getProperty("java.class.version"); //$NON-NLS-1$
  if (classFileVersion == null) {
    // by default we don't support a class file version we cannot recognize
    return false;
  }
  int index = classFileVersion.indexOf('.');
  if (index == -1) {
    // by default we don't support a class file version we cannot recognize
    return false;
  }
  int majorVersion;
  try {
    majorVersion = Integer.parseInt(classFileVersion.substring(0, index));
  } catch (NumberFormatException e) {
    // by default we don't support a class file version we cannot recognize
    return false;
  }
  switch(majorVersion) {
    case 45 : // 1.0 and 1.1
      return ClassFileConstants.JDK1_1 >= minimalSupportedVersion;
    case 46 : // 1.2
      return ClassFileConstants.JDK1_2 >= minimalSupportedVersion;
    case 47 : // 1.3
      return ClassFileConstants.JDK1_3 >= minimalSupportedVersion;
    case 48 : // 1.4
      return ClassFileConstants.JDK1_4 >= minimalSupportedVersion;
    case 49 : // 1.5
      return ClassFileConstants.JDK1_5 >= minimalSupportedVersion;
    case 50 : // 1.6
      return ClassFileConstants.JDK1_6 >= minimalSupportedVersion;
    case 51 : // 1.7
      return ClassFileConstants.JDK1_7 >= minimalSupportedVersion;
  }
  // unknown version
  return false;
}
/*
*  Low-level API performing the actual compilation
*/
public boolean compile(String[] argv) {

  // decode command line arguments
  try {
    configure(argv);
    if (this.proceed) {
//        if (this.verbose) {
//          System.out.println(new CompilerOptions(this.options));
//        }
      if (this.showProgress) this.logger.compiling();
      for (int i = 0; i < this.repetitions; i++) {
        this.globalProblemsCount = 0;
        this.globalErrorsCount = 0;
        this.globalWarningsCount = 0;
        this.globalTasksCount = 0;
        this.lineCount = 0;
        this.exportedClassFilesCounter = 0;

        if (this.repetitions > 1) {
          this.logger.flush();
          this.logger.logRepetition(i, this.repetitions);
        }
        // request compilation
        performCompilation();
      }
      if (this.times != null) {
        this.logger.logAverage(this.times, this.lineCount);
      }
      if (this.showProgress) this.logger.printNewLine();
    }
    if (this.systemExitWhenFinished) {
      this.logger.flush();
      this.logger.close();
      System.exit(this.globalErrorsCount > 0 ? -1 : 0);
    }
  } catch (InvalidInputException e) {
    this.logger.logException(e);
    if (this.systemExitWhenFinished) {
      this.logger.flush();
      this.logger.close();
      System.exit(-1);
    }
    return false;
  } catch (RuntimeException e) { // internal compiler failure
    this.logger.logException(e);
    if (this.systemExitWhenFinished) {
      this.logger.flush();
      this.logger.close();
      System.exit(-1);
    }
    return false;
  } finally {
    this.logger.flush();
    this.logger.close();
  }
  if (this.globalErrorsCount == 0)
    return true;
  return false;
}

/*
* External API
* Handle a single warning token.
*/
protected void handleWarningToken(String token, boolean isEnabling, boolean useEnableJavadoc) throws InvalidInputException {
  if (token.equals("constructorName")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportMethodWithConstructorName,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("pkgDefaultMethod") || token.equals("packageDefaultMethod")/*backward compatible*/ ) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("maskedCatchBlock") || token.equals("maskedCatchBlocks")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportHiddenCatchBlock,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("deprecation")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode,
      CompilerOptions.DISABLED);
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod,
      CompilerOptions.DISABLED);
  } else if (token.equals("allDeprecation")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecationInDeprecatedCode,
      isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
    this.options.put(
      CompilerOptions.OPTION_ReportDeprecationWhenOverridingDeprecatedMethod,
      isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
  } else if (token.equals("unusedLocal") || token.equals("unusedLocals")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedLocal,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unusedArgument") || token.equals("unusedArguments")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedParameter,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unusedImport") || token.equals("unusedImports")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedImport,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unusedPrivate")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedPrivateMember,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unusedLabel")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedLabel,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("localHiding")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportLocalVariableHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("fieldHiding")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportFieldHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("specialParamHiding")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportSpecialParameterHidingField,
      isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
  } else if (token.equals("conditionAssign")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportPossibleAccidentalBooleanAssignment,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    } else if (token.equals("syntheticAccess") //$NON-NLS-1$
        || token.equals("synthetic-access")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("nls")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("staticReceiver")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportNonStaticAccessToStatic,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("indirectStatic")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportIndirectStaticAccess,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("noEffectAssign")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportNoEffectAssignment,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("intfNonInherited") || token.equals("interfaceNonInherited")/*backward compatible*/) { //$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportIncompatibleNonInheritedInterfaceMethod,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("charConcat") || token.equals("noImplicitStringConversion")/*backward compatible*/) {//$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportNoImplicitStringConversion,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("semicolon")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportEmptyStatement,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("serial")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportMissingSerialVersion,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("emptyBlock")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUndocumentedEmptyBlock,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("uselessTypeCheck")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnnecessaryTypeCheck,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unchecked") || token.equals("unsafe")) {//$NON-NLS-1$ //$NON-NLS-2$
    this.options.put(
      CompilerOptions.OPTION_ReportUncheckedTypeOperation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("raw")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportRawTypeReference,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("finalBound")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportFinalParameterBound,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("suppress")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_SuppressWarnings,
      isEnabling ? CompilerOptions.ENABLED : CompilerOptions.DISABLED);
  } else if (token.equals("warningToken")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnhandledWarningToken,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unnecessaryElse")) {//$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnnecessaryElse,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("javadoc")) {//$NON-NLS-1$
    if (!useEnableJavadoc) {
      this.options.put(
        CompilerOptions.OPTION_DocCommentSupport,
        isEnabling ? CompilerOptions.ENABLED: CompilerOptions.DISABLED);
    }
    // if disabling then it's not necessary to set other javadoc options
    if (isEnabling) {
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadoc,
        CompilerOptions.WARNING);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTags,
        CompilerOptions.ENABLED);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTagsDeprecatedRef,
        CompilerOptions.DISABLED);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTagsNotVisibleRef,
        CompilerOptions.DISABLED);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility,
        CompilerOptions.PRIVATE);
      this.options.put(
        CompilerOptions.OPTION_ReportMissingJavadocTags,
        CompilerOptions.WARNING);
      this.options.put(
        CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility,
        CompilerOptions.PRIVATE);
    }
  } else if (token.equals("allJavadoc")) { //$NON-NLS-1$
    if (!useEnableJavadoc) {
      this.options.put(
        CompilerOptions.OPTION_DocCommentSupport,
        isEnabling ? CompilerOptions.ENABLED: CompilerOptions.DISABLED);
    }
    // if disabling then it's not necessary to set other javadoc options
    if (isEnabling) {
      this.options.put(
      CompilerOptions.OPTION_ReportInvalidJavadoc,
      CompilerOptions.WARNING);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTags,
        CompilerOptions.ENABLED);
      this.options.put(
        CompilerOptions.OPTION_ReportInvalidJavadocTagsVisibility,
        CompilerOptions.PRIVATE);
      this.options.put(
        CompilerOptions.OPTION_ReportMissingJavadocTags,
        CompilerOptions.WARNING);
      this.options.put(
        CompilerOptions.OPTION_ReportMissingJavadocTagsVisibility,
        CompilerOptions.PRIVATE);
      this.options.put(
        CompilerOptions.OPTION_ReportMissingJavadocComments,
        CompilerOptions.WARNING);
    }
  } else if (token.startsWith("tasks")) { //$NON-NLS-1$
    String taskTags = Util.EMPTY_STRING;
    int start = token.indexOf('(');
    int end = token.indexOf(')');
    if (start >= 0 && end >= 0 && start < end){
      taskTags = token.substring(start+1, end).trim();
      taskTags = taskTags.replace('|',',');
    }
    if (taskTags.length() == 0){
      throw new InvalidInputException(this.bind("configure.invalidTaskTag", token)); //$NON-NLS-1$
    }
    this.options.put(
      CompilerOptions.OPTION_TaskTags,
      isEnabling ? taskTags : Util.EMPTY_STRING);
  } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportAssertIdentifier,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("enumIdentifier")) { //$NON-NLS-1$
    this.options.put(
        CompilerOptions.OPTION_ReportEnumIdentifier,
        isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("finally")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportFinallyBlockNotCompletingNormally,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unusedThrown")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedDeclaredThrownException,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unqualifiedField") //$NON-NLS-1$
      || token.equals("unqualified-field-access")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnqualifiedFieldAccess,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("typeHiding")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportTypeParameterHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("varargsCast")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportVarargsArgumentNeedCast,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("null")) { //$NON-NLS-1$
    if (isEnabling) {
      this.options.put(CompilerOptions.OPTION_ReportNullReference,
          CompilerOptions.WARNING);
      this.options.put(CompilerOptions.OPTION_ReportPotentialNullReference,
          CompilerOptions.WARNING);
      this.options.put(CompilerOptions.OPTION_ReportRedundantNullCheck,
          CompilerOptions.WARNING);
    } else {
      this.options.put(CompilerOptions.OPTION_ReportNullReference,
          CompilerOptions.IGNORE);
      this.options.put(CompilerOptions.OPTION_ReportPotentialNullReference,
          CompilerOptions.IGNORE);
      this.options.put(CompilerOptions.OPTION_ReportRedundantNullCheck,
          CompilerOptions.IGNORE);
    }
  } else if (token.equals("nullDereference")) { //$NON-NLS-1$
    if (isEnabling) {
      this.options.put(CompilerOptions.OPTION_ReportNullReference,
          CompilerOptions.WARNING);
    } else {
      this.options.put(CompilerOptions.OPTION_ReportNullReference,
          CompilerOptions.IGNORE);
      this.options.put(CompilerOptions.OPTION_ReportPotentialNullReference,
          CompilerOptions.IGNORE);
      this.options.put(CompilerOptions.OPTION_ReportRedundantNullCheck,
          CompilerOptions.IGNORE);
    }
  } else if (token.equals("boxing")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportAutoboxing,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("over-ann")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportMissingOverrideAnnotation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("dep-ann")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportMissingDeprecatedAnnotation,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("intfAnnotation")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportAnnotationSuperInterface,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("enumSwitch") //$NON-NLS-1$
      || token.equals("incomplete-switch")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportIncompleteEnumSwitch,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("hiding")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportHiddenCatchBlock,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportLocalVariableHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportFieldHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportTypeParameterHiding,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("static-access")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportNonStaticAccessToStatic,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportIndirectStaticAccess,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("unused")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedLocal,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedParameter,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedImport,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedPrivateMember,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
      CompilerOptions.OPTION_ReportUnusedDeclaredThrownException,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
    this.options.put(
        CompilerOptions.OPTION_ReportUnusedLabel,
        isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("paramAssign")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportParameterAssignment,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("discouraged")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportDiscouragedReference,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("forbidden")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportForbiddenReference,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("fallthrough")) { //$NON-NLS-1$
    this.options.put(
      CompilerOptions.OPTION_ReportFallthroughCase,
      isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else if (token.equals("super")) { //$NON-NLS-1$
    this.options.put(
        CompilerOptions.OPTION_ReportOverridingMethodWithoutSuperInvocation,
        isEnabling ? CompilerOptions.WARNING : CompilerOptions.IGNORE);
  } else {
    throw new InvalidInputException(this.bind("configure.invalidWarning", token)); //$NON-NLS-1$
  }
}
/*
* External API
*/
protected ArrayList handleBootclasspath(ArrayList bootclasspaths, String customEncoding) throws InvalidInputException {
   final int bootclasspathsSize = bootclasspaths == null ? 0 : bootclasspaths.size();
  if (bootclasspathsSize != 0) {
    String[] paths = new String[bootclasspathsSize];
    bootclasspaths.toArray(paths);
    bootclasspaths.clear();
    for (int i = 0; i < bootclasspathsSize; i++) {
      processPathEntries(DEFAULT_SIZE_CLASSPATH, bootclasspaths,
        paths[i], customEncoding, false, true);
    }
  } else {
     bootclasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
    /* no bootclasspath specified
     * we can try to retrieve the default librairies of the VM used to run
     * the batch compiler
     */
     String javaversion = System.getProperty("java.version");//$NON-NLS-1$
     if (javaversion != null && javaversion.equalsIgnoreCase("1.1.8")) { //$NON-NLS-1$
      this.logger.logWrongJDK();
      this.proceed = false;
      return null;
     }

     /*
      * Handle >= JDK 1.2.2 settings: retrieve the bootclasspath
      */
    // check bootclasspath properties for Sun, JRockit and Harmony VMs
    String bootclasspathProperty = System.getProperty("sun.boot.class.path"); //$NON-NLS-1$
    if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
      // IBM J9 VMs
      bootclasspathProperty = System.getProperty("vm.boot.class.path"); //$NON-NLS-1$
      if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) {
        // Harmony using IBM VME
        bootclasspathProperty = System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$
      }
    }
    if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) {
      StringTokenizer tokenizer = new StringTokenizer(bootclasspathProperty, File.pathSeparator);
      String token;
      while (tokenizer.hasMoreTokens()) {
        token = tokenizer.nextToken();
        FileSystem.Classpath currentClasspath = FileSystem
            .getClasspath(token, customEncoding, null);
        if (currentClasspath != null) {
          bootclasspaths.add(currentClasspath);
        }
      }
    } else {
      // try to get all jars inside the lib folder of the java home
      final File javaHome = getJavaHome();
      if (javaHome != null) {
        File[] directoriesToCheck = null;
        if (System.getProperty("os.name").startsWith("Mac")) {//$NON-NLS-1$//$NON-NLS-2$
          directoriesToCheck = new File[] {
            new File(javaHome, "../Classes"), //$NON-NLS-1$
          };
        } else {
          // fall back to try to retrieve them out of the lib directory
          directoriesToCheck = new File[] {
            new File(javaHome, "lib") //$NON-NLS-1$
          };
        }
        File[][] systemLibrariesJars = getLibrariesFiles(directoriesToCheck);
        if (systemLibrariesJars != null) {
          for (int i = 0, max = systemLibrariesJars.length; i < max; i++) {
            File[] current = systemLibrariesJars[i];
            if (current != null) {
              for (int j = 0, max2 = current.length; j < max2; j++) {
                FileSystem.Classpath classpath =
                  FileSystem.getClasspath(current[j].getAbsolutePath(),
                    null, false, null, null);
                if (classpath != null) {
                  bootclasspaths.add(classpath);
                }
              }
            }
          }
        }
      }
    }
  }
  return bootclasspaths;
}
/*
* External API
*/
protected ArrayList handleClasspath(ArrayList classpaths, String customEncoding) throws InvalidInputException {
  final int classpathsSize = classpaths == null ? 0 : classpaths.size();
  if (classpathsSize != 0) {
    String[] paths = new String[classpathsSize];
    classpaths.toArray(paths);
    classpaths.clear();
    for (int i = 0; i < classpathsSize; i++) {
      processPathEntries(DEFAULT_SIZE_CLASSPATH, classpaths, paths[i],
          customEncoding, false, true);
    }
  } else {
    // no user classpath specified.
    classpaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
    String classProp = System.getProperty("java.class.path"); //$NON-NLS-1$
    if ((classProp == null) || (classProp.length() == 0)) {
      this.logger.logNoClasspath();
      classpaths.add(FileSystem.getClasspath(System.getProperty("user.dir"), customEncoding, null));//$NON-NLS-1$
    } else {
      StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
      String token;
      while (tokenizer.hasMoreTokens()) {
        token = tokenizer.nextToken();
        FileSystem.Classpath currentClasspath = FileSystem
            .getClasspath(token, customEncoding, null);
        if (currentClasspath != null) {
          classpaths.add(currentClasspath);
        } else if (token.length() != 0) {
          this.logger.logIncorrectClasspath(token);
        }
      }
    }
  }
  return classpaths;
}
/*
* External API
* Handle extdirs processing
*/
protected ArrayList handleExtdirs(ArrayList extdirsClasspaths) {
   final File javaHome = getJavaHome();

  /*
   * Feed extDirClasspath according to:
   * - -extdirs first if present;
   * - else java.ext.dirs if defined;
   * - else default extensions directory for the platform.
   */
  if (extdirsClasspaths == null) {
    extdirsClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
    String extdirsStr = System.getProperty("java.ext.dirs"); //$NON-NLS-1$
    if (extdirsStr == null) {
      extdirsClasspaths.add(javaHome.getAbsolutePath() + "/lib/ext"); //$NON-NLS-1$
    } else {
      StringTokenizer tokenizer = new StringTokenizer(extdirsStr, File.pathSeparator);
      while (tokenizer.hasMoreTokens())
        extdirsClasspaths.add(tokenizer.nextToken());
    }
  }

  /*
   * Feed extdirsClasspath with the entries found into the directories listed by
   * extdirsNames.
   */
  if (extdirsClasspaths.size() != 0) {
    File[] directoriesToCheck = new File[extdirsClasspaths.size()];
    for (int i = 0; i < directoriesToCheck.length; i++)
      directoriesToCheck[i] = new File((String) extdirsClasspaths.get(i));
    extdirsClasspaths.clear();
    File[][] extdirsJars = getLibrariesFiles(directoriesToCheck);
    if (extdirsJars != null) {
      for (int i = 0, max = extdirsJars.length; i < max; i++) {
        File[] current = extdirsJars[i];
        if (current != null) {
          for (int j = 0, max2 = current.length; j < max2; j++) {
            FileSystem.Classpath classpath =
              FileSystem.getClasspath(
                  current[j].getAbsolutePath(),
                  null, null);
            if (classpath != null) {
              extdirsClasspaths.add(classpath);
            }
          }
        } else if (directoriesToCheck[i].isFile()) {
          this.logger.logIncorrectExtDirsEntry(directoriesToCheck[i].getAbsolutePath());
        }
      }
    }
  }

  return extdirsClasspaths;
}
/*
* External API
*/
protected ArrayList handleEndorseddirs(ArrayList endorsedDirClasspaths) {
   final File javaHome = getJavaHome();
  /*
   * Feed endorsedDirClasspath according to:
   * - -endorseddirs first if present;
   * - else java.endorsed.dirs if defined;
   * - else default extensions directory for the platform. (/lib/endorsed)
   */
  if (endorsedDirClasspaths == null) {
    endorsedDirClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
    String endorsedDirsStr = System.getProperty("java.endorsed.dirs"); //$NON-NLS-1$
    if (endorsedDirsStr == null) {
      if (javaHome != null) {
        endorsedDirClasspaths.add(javaHome.getAbsolutePath() + "/lib/endorsed"); //$NON-NLS-1$
      }
    } else {
      StringTokenizer tokenizer = new StringTokenizer(endorsedDirsStr, File.pathSeparator);
      while (tokenizer.hasMoreTokens()) {
        endorsedDirClasspaths.add(tokenizer.nextToken());
      }
    }
  }

  /*
   * Feed extdirsClasspath with the entries found into the directories listed by
   * extdirsNames.
   */
  if (endorsedDirClasspaths.size() != 0) {
    File[] directoriesToCheck = new File[endorsedDirClasspaths.size()];
    for (int i = 0; i < directoriesToCheck.length; i++)
      directoriesToCheck[i] = new File((String) endorsedDirClasspaths.get(i));
    endorsedDirClasspaths.clear();
    File[][] endorsedDirsJars = getLibrariesFiles(directoriesToCheck);
    if (endorsedDirsJars != null) {
      for (int i = 0, max = endorsedDirsJars.length; i < max; i++) {
        File[] current = endorsedDirsJars[i];
        if (current != null) {
          for (int j = 0, max2 = current.length; j < max2; j++) {
            FileSystem.Classpath classpath =
              FileSystem.getClasspath(
                  current[j].getAbsolutePath(),
                  null, null);
            if (classpath != null) {
              endorsedDirClasspaths.add(classpath);
            }
          }
        } else if (directoriesToCheck[i].isFile()) {
          this.logger.logIncorrectEndorsedDirsEntry(directoriesToCheck[i].getAbsolutePath());
        }
      }
    }
  }
  return endorsedDirClasspaths;
}

/*
Decode the command line arguments
*/
public void configure(String[] argv) throws InvalidInputException {

  if ((argv == null) || (argv.length == 0)) {
    printUsage();
    return;
  }

  final int INSIDE_CLASSPATH_start = 1;
  final int INSIDE_DESTINATION_PATH = 3;
  final int INSIDE_TARGET = 4;
  final int INSIDE_LOG = 5;
  final int INSIDE_REPETITION = 6;
  final int INSIDE_SOURCE = 7;
  final int INSIDE_DEFAULT_ENCODING = 8;
  final int INSIDE_BOOTCLASSPATH_start = 9;
  final int INSIDE_MAX_PROBLEMS = 11;
  final int INSIDE_EXT_DIRS = 12;
  final int INSIDE_SOURCE_PATH_start = 13;
  final int INSIDE_ENDORSED_DIRS = 15;
  final int INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH = 16;
  final int INSIDE_PROCESSOR_PATH_start = 17;
  final int INSIDE_PROCESSOR_start = 18;
  final int INSIDE_S_start = 19;
  final int INSIDE_CLASS_NAMES = 20;

  final int DEFAULT = 0;
  ArrayList bootclasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
  String sourcepathClasspathArg = null;
  ArrayList sourcepathClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
  ArrayList classpaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
  ArrayList extdirsClasspaths = null;
  ArrayList endorsedDirClasspaths = null;

  int index = -1;
  int filesCount = 0;
  int classCount = 0;
  int argCount = argv.length;
  int mode = DEFAULT;
  this.repetitions = 0;
  boolean printUsageRequired = false;
  String usageSection = null;
  boolean printVersionRequired = false;

  boolean didSpecifyDefaultEncoding = false;
  boolean didSpecifyDeprecation = false;
  boolean didSpecifyWarnings = false;
  boolean useEnableJavadoc = false;
  boolean didSpecifyCompliance = false;
  boolean didSpecifyDisabledAnnotationProcessing = false;

  String customEncoding = null;
  String customDestinationPath = null;
  String currentSourceDirectory = null;
  String currentArg = Util.EMPTY_STRING;

  // expand the command line if necessary
  boolean needExpansion = false;
  loop: for (int i = 0; i < argCount; i++) {
      if (argv[i].startsWith("@")) { //$NON-NLS-1$
        needExpansion = true;
        break loop;
      }
  }

  String[] newCommandLineArgs = null;
  if (needExpansion) {
    newCommandLineArgs = new String[argCount];
    index = 0;
    for (int i = 0; i < argCount; i++) {
      String[] newArgs = null;
      String arg = argv[i].trim();
      if (arg.startsWith("@")) { //$NON-NLS-1$
        try {
          LineNumberReader reader = new LineNumberReader(new StringReader(new String(Util.getFileCharContent(new File(arg.substring(1)), null))));
          StringBuffer buffer = new StringBuffer();
          String line;
          while((line = reader.readLine()) != null) {
            line = line.trim();
            if (!line.startsWith("#")) { //$NON-NLS-1$
              buffer.append(line).append(" "); //$NON-NLS-1$
            }
          }
          newArgs = tokenize(buffer.toString());
        } catch(IOException e) {
          throw new InvalidInputException(
            this.bind("configure.invalidexpansionargumentname", arg)); //$NON-NLS-1$
        }
      }
      if (newArgs != null) {
        int newCommandLineArgsLength = newCommandLineArgs.length;
        int newArgsLength = newArgs.length;
        System.arraycopy(newCommandLineArgs, 0, (newCommandLineArgs = new String[newCommandLineArgsLength + newArgsLength - 1]), 0, index);
        System.arraycopy(newArgs, 0, newCommandLineArgs, index, newArgsLength);
        index += newArgsLength;
      } else {
        newCommandLineArgs[index++] = arg;
      }
    }
    index = -1;
  } else {
    newCommandLineArgs = argv;
    for (int i = 0; i < argCount; i++) {
      newCommandLineArgs[i] = newCommandLineArgs[i].trim();
    }
  }
  argCount = newCommandLineArgs.length;
  this.expandedCommandLine = newCommandLineArgs;
  while (++index < argCount) {

    if (customEncoding != null) {
      throw new InvalidInputException(
        this.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$
    }

    currentArg = newCommandLineArgs[index];

    switch(mode) {
      case DEFAULT :
        if (currentArg.startsWith("[")) { //$NON-NLS-1$
          throw new InvalidInputException(
            this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                  currentArg));
        }

        if (currentArg.endsWith("]")) { //$NON-NLS-1$
          // look for encoding specification
          int encodingStart = currentArg.indexOf('[') + 1;
          if (encodingStart <= 1) {
            throw new InvalidInputException(
                this.bind("configure.unexpectedBracket", currentArg)); //$NON-NLS-1$
          }
          int encodingEnd = currentArg.length() - 1;
          if (encodingStart >= 1) {
            if (encodingStart < encodingEnd) {
              customEncoding = currentArg.substring(encodingStart, encodingEnd);
              try { // ensure encoding is supported
                new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding);
              } catch (UnsupportedEncodingException e) {
                throw new InvalidInputException(
                  this.bind("configure.unsupportedEncoding", customEncoding)); //$NON-NLS-1$
              }
            }
            currentArg = currentArg.substring(0, encodingStart - 1);
          }
        }

        if (currentArg.endsWith(SuffixConstants.SUFFIX_STRING_java)) {
          if (this.filenames == null) {
            this.filenames = new String[argCount - index];
            this.encodings = new String[argCount - index];
            this.destinationPaths = new String[argCount - index];
          } else if (filesCount == this.filenames.length) {
            int length = this.filenames.length;
            System.arraycopy(
              this.filenames,
              0,
              (this.filenames = new String[length + argCount - index]),
              0,
              length);
            System.arraycopy(
              this.encodings,
              0,
              (this.encodings = new String[length + argCount - index]),
              0,
              length);
            System.arraycopy(
              this.destinationPaths,
              0,
              (this.destinationPaths = new String[length + argCount - index]),
              0,
              length);
          }
          this.filenames[filesCount] = currentArg;
          this.encodings[filesCount++] = customEncoding;
          // destination path cannot be specified upon an individual file
          customEncoding = null;
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-log")) { //$NON-NLS-1$
          if (this.log != null)
            throw new InvalidInputException(
              this.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$
          mode = INSIDE_LOG;
          continue;
        }
        if (currentArg.equals("-repeat")) { //$NON-NLS-1$
          if (this.repetitions > 0)
            throw new InvalidInputException(
              this.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$
          mode = INSIDE_REPETITION;
          continue;
        }
        if (currentArg.equals("-maxProblems")) { //$NON-NLS-1$
          if (this.maxProblems > 0)
            throw new InvalidInputException(
              this.bind("configure.duplicateMaxProblems", currentArg)); //$NON-NLS-1$
          mode = INSIDE_MAX_PROBLEMS;
          continue;
        }
        if (currentArg.equals("-source")) { //$NON-NLS-1$
          mode = INSIDE_SOURCE;
          continue;
        }
        if (currentArg.equals("-encoding")) { //$NON-NLS-1$
          mode = INSIDE_DEFAULT_ENCODING;
          continue;
        }
        if (currentArg.equals("-1.3")) { //$NON-NLS-1$
          if (didSpecifyCompliance) {
            throw new InvalidInputException(
              this.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$
          }
          didSpecifyCompliance = true;
          this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-1.4")) { //$NON-NLS-1$
          if (didSpecifyCompliance) {
            throw new InvalidInputException(
              this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
          }
          didSpecifyCompliance = true;
          this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-1.5") || currentArg.equals("-5") || currentArg.equals("-5.0")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          if (didSpecifyCompliance) {
            throw new InvalidInputException(
              this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
          }
          didSpecifyCompliance = true;
          this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-1.6") || currentArg.equals("-6") || currentArg.equals("-6.0")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          if (didSpecifyCompliance) {
            throw new InvalidInputException(
              this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
          }
          didSpecifyCompliance = true;
          this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-1.7") || currentArg.equals("-7") || currentArg.equals("-7.0")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
          if (didSpecifyCompliance) {
            throw new InvalidInputException(
              this.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
          }
          didSpecifyCompliance = true;
          this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_7);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-d")) { //$NON-NLS-1$
          if (this.destinationPath != null) {
            StringBuffer errorMessage = new StringBuffer();
            errorMessage.append(currentArg);
            if ((index + 1) < argCount) {
              errorMessage.append(' ');
              errorMessage.append(newCommandLineArgs[index + 1]);
            }
            throw new InvalidInputException(
              this.bind("configure.duplicateOutputPath", errorMessage.toString())); //$NON-NLS-1$
          }
          mode = INSIDE_DESTINATION_PATH;
          continue;
        }
        if (currentArg.equals("-classpath") //$NON-NLS-1$
          || currentArg.equals("-cp")) { //$NON-NLS-1$
          mode = INSIDE_CLASSPATH_start;
          continue;
        }
        if (currentArg.equals("-bootclasspath")) {//$NON-NLS-1$
          if (bootclasspaths.size() > 0) {
            StringBuffer errorMessage = new StringBuffer();
            errorMessage.append(currentArg);
            if ((index + 1) < argCount) {
              errorMessage.append(' ');
              errorMessage.append(newCommandLineArgs[index + 1]);
            }
            throw new InvalidInputException(
              this.bind("configure.duplicateBootClasspath", errorMessage.toString())); //$NON-NLS-1$
          }
          mode = INSIDE_BOOTCLASSPATH_start;
          continue;
        }
        if (currentArg.equals("-sourcepath")) {//$NON-NLS-1$
          if (sourcepathClasspathArg != null) {
            StringBuffer errorMessage = new StringBuffer();
            errorMessage.append(currentArg);
            if ((index + 1) < argCount) {
              errorMessage.append(' ');
              errorMessage.append(newCommandLineArgs[index + 1]);
            }
            throw new InvalidInputException(
              this.bind("configure.duplicateSourcepath", errorMessage.toString())); //$NON-NLS-1$
          }
          mode = INSIDE_SOURCE_PATH_start;
          continue;
        }
        if (currentArg.equals("-extdirs")) {//$NON-NLS-1$
          if (extdirsClasspaths != null) {
            StringBuffer errorMessage = new StringBuffer();
            errorMessage.append(currentArg);
            if ((index + 1) < argCount) {
              errorMessage.append(' ');
              errorMessage.append(newCommandLineArgs[index + 1]);
            }
            throw new InvalidInputException(
              this.bind("configure.duplicateExtDirs", errorMessage.toString())); //$NON-NLS-1$
          }
          mode = INSIDE_EXT_DIRS;
          continue;
        }
        if (currentArg.equals("-endorseddirs")) { //$NON-NLS-1$
          if (endorsedDirClasspaths != null) {
            StringBuffer errorMessage = new StringBuffer();
            errorMessage.append(currentArg);
            if ((index + 1) < argCount) {
              errorMessage.append(' ');
              errorMessage.append(newCommandLineArgs[index + 1]);
            }
            throw new InvalidInputException(
              this.bind("configure.duplicateEndorsedDirs", errorMessage.toString())); //$NON-NLS-1$
          }
          mode = INSIDE_ENDORSED_DIRS;
          continue;
        }
        if (currentArg.equals("-progress")) { //$NON-NLS-1$
          mode = DEFAULT;
          this.showProgress = true;
          continue;
        }
        if (currentArg.equals("-proceedOnError")) { //$NON-NLS-1$
          mode = DEFAULT;
          this.proceedOnError = true;
          continue;
        }
        if (currentArg.equals("-time")) { //$NON-NLS-1$
          mode = DEFAULT;
          this.timing = true;
          continue;
        }
        if (currentArg.equals("-version") //$NON-NLS-1$
            || currentArg.equals("-v")) { //$NON-NLS-1$
          this.logger.logVersion(true);
          this.proceed = false;
          return;
        }
        if (currentArg.equals("-showversion")) { //$NON-NLS-1$
          printVersionRequired = true;
          mode = DEFAULT;
          continue;
        }
        if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$
          didSpecifyDeprecation = true;
          this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-help") || currentArg.equals("-?")) { //$NON-NLS-1$ //$NON-NLS-2$
          printUsageRequired = true;
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-help:warn") || //$NON-NLS-1$
            currentArg.equals("-?:warn")) { //$NON-NLS-1$
          printUsageRequired = true;
          usageSection = "misc.usage.warn"; //$NON-NLS-1$
          continue;
        }
        if (currentArg.equals("-noExit")) { //$NON-NLS-1$
          this.systemExitWhenFinished = false;
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-verbose")) { //$NON-NLS-1$
          this.verbose = true;
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$
          this.produceRefInfo = true;
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-inlineJSR")) { //$NON-NLS-1$
            mode = DEFAULT;
          this.options.put(
              CompilerOptions.OPTION_InlineJsr,
              CompilerOptions.ENABLED);
            continue;
        }
        if (currentArg.startsWith("-g")) { //$NON-NLS-1$
          mode = DEFAULT;
          String debugOption = currentArg;
          int length = currentArg.length();
          if (length == 2) {
            this.options.put(
              CompilerOptions.OPTION_LocalVariableAttribute,
              CompilerOptions.GENERATE);
            this.options.put(
              CompilerOptions.OPTION_LineNumberAttribute,
              CompilerOptions.GENERATE);
            this.options.put(
              CompilerOptions.OPTION_SourceFileAttribute,
              CompilerOptions.GENERATE);
            continue;
          }
          if (length > 3) {
            this.options.put(
              CompilerOptions.OPTION_LocalVariableAttribute,
              CompilerOptions.DO_NOT_GENERATE);
            this.options.put(
              CompilerOptions.OPTION_LineNumberAttribute,
              CompilerOptions.DO_NOT_GENERATE);
            this.options.put(
              CompilerOptions.OPTION_SourceFileAttribute,
              CompilerOptions.DO_NOT_GENERATE);
            if (length == 7 && debugOption.equals("-g:" + NONE)) //$NON-NLS-1$
              continue;
            StringTokenizer tokenizer =
              new StringTokenizer(debugOption.substring(3, debugOption.length()), ","); //$NON-NLS-1$
            while (tokenizer.hasMoreTokens()) {
              String token = tokenizer.nextToken();
              if (token.equals("vars")) { //$NON-NLS-1$
                this.options.put(
                  CompilerOptions.OPTION_LocalVariableAttribute,
                  CompilerOptions.GENERATE);
              } else if (token.equals("lines")) { //$NON-NLS-1$
                this.options.put(
                  CompilerOptions.OPTION_LineNumberAttribute,
                  CompilerOptions.GENERATE);
              } else if (token.equals("source")) { //$NON-NLS-1$
                this.options.put(
                  CompilerOptions.OPTION_SourceFileAttribute,
                  CompilerOptions.GENERATE);
              } else {
                throw new InvalidInputException(
                  this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
              }
            }
            continue;
          }
          throw new InvalidInputException(
            this.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
        }
        if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$
          disableWarnings();
          mode = DEFAULT;
          continue;
        }
        if (currentArg.startsWith("-warn")) { //$NON-NLS-1$
          mode = DEFAULT;
          String warningOption = currentArg;
          int length = currentArg.length();
          if (length == 10 && warningOption.equals("-warn:" + NONE)) { //$NON-NLS-1$
            disableWarnings();
            continue;
          }
          if (length <= 6) {
            throw new InvalidInputException(
              this.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$
          }
          int warnTokenStart;
          boolean isEnabling;
          switch (warningOption.charAt(6)) {
            case '+' :
              warnTokenStart = 7;
              isEnabling = true;
              break;
            case '-' :
              warnTokenStart = 7;
              isEnabling = false; // mentionned warnings are disabled
              break;
            default:
              warnTokenStart = 6;
              // clear default warning level
              // but allow multiple warning option on the command line
              if (!didSpecifyWarnings) disableWarnings();
              isEnabling = true;
          }

          StringTokenizer tokenizer =
            new StringTokenizer(warningOption.substring(warnTokenStart, warningOption.length()), ","); //$NON-NLS-1$
          int tokenCounter = 0;

          if (didSpecifyDeprecation) {  // deprecation could have also been set through -deprecation option
            this.options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
          }

          while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            tokenCounter++;
            handleWarningToken(token, isEnabling, useEnableJavadoc);
          }
          if (tokenCounter == 0)
            throw new InvalidInputException(
              this.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$
          didSpecifyWarnings = true;
          continue;
        }
        if (currentArg.equals("-target")) { //$NON-NLS-1$
          mode = INSIDE_TARGET;
          continue;
        }
        if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$
          this.options.put(
            CompilerOptions.OPTION_PreserveUnusedLocal,
            CompilerOptions.PRESERVE);
            mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-enableJavadoc")) {//$NON-NLS-1$
            mode = DEFAULT;
          this.options.put(
            CompilerOptions.OPTION_DocCommentSupport,
            CompilerOptions.ENABLED);
          useEnableJavadoc = true;
          continue;
        }
        if (currentArg.equals("-Xemacs")) { //$NON-NLS-1$
          mode = DEFAULT;
          this.logger.setEmacs();
          continue;
        }
        // annotation processing
        if (currentArg.startsWith("-A")) { //$NON-NLS-1$
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-processorpath")) { //$NON-NLS-1$
          mode = INSIDE_PROCESSOR_PATH_start;
          continue;
        }
        if (currentArg.equals("-processor")) { //$NON-NLS-1$
          mode = INSIDE_PROCESSOR_start;
          continue;
        }
        if (currentArg.equals("-proc:only")) { //$NON-NLS-1$
          this.options.put(
            CompilerOptions.OPTION_GenerateClassFiles,
            CompilerOptions.DISABLED);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-proc:none")) { //$NON-NLS-1$
          didSpecifyDisabledAnnotationProcessing = true;
          this.options.put(
            CompilerOptions.OPTION_Process_Annotations,
            CompilerOptions.DISABLED);
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-s")) { //$NON-NLS-1$
          mode = INSIDE_S_start;
          continue;
        }
        if (currentArg.equals("-XprintProcessorInfo") //$NON-NLS-1$
            || currentArg.equals("-XprintRounds")) { //$NON-NLS-1$
          mode = DEFAULT;
          continue;
        }
        // tolerated javac options - quietly filtered out
        if (currentArg.startsWith("-X")) { //$NON-NLS-1$
          mode = DEFAULT;
          continue;
        }
        if (currentArg.startsWith("-J")) { //$NON-NLS-1$
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-O")) { //$NON-NLS-1$
          mode = DEFAULT;
          continue;
        }
        if (currentArg.equals("-classNames")) { //$NON-NLS-1$
          mode = INSIDE_CLASS_NAMES;
          continue;
        }
        break;
      case INSIDE_TARGET :
        if (this.didSpecifyTarget) {
          throw new InvalidInputException(
            this.bind("configure.duplicateTarget", currentArg));//$NON-NLS-1$
        }
        this.didSpecifyTarget = true;
        if (currentArg.equals("1.1")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
        } else if (currentArg.equals("1.2")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
        } else if (currentArg.equals("1.3")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_3);
        } else if (currentArg.equals("1.4")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
        } else if (currentArg.equals("1.5") || currentArg.equals("5") || currentArg.equals("5.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
        } else if (currentArg.equals("1.6") || currentArg.equals("6") || currentArg.equals("6.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
        } else if (currentArg.equals("1.7") || currentArg.equals("7") || currentArg.equals("7.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
        } else if (currentArg.equals("jsr14")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_JSR14);
        } else {
          throw new InvalidInputException(this.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$
        }
        mode = DEFAULT;
        continue;
      case INSIDE_LOG :
        this.log = currentArg;
        mode = DEFAULT;
        continue;
      case INSIDE_REPETITION :
        try {
          this.repetitions = Integer.parseInt(currentArg);
          if (this.repetitions <= 0) {
            throw new InvalidInputException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$
          }
        } catch (NumberFormatException e) {
          throw new InvalidInputException(this.bind("configure.repetition", currentArg)); //$NON-NLS-1$
        }
        mode = DEFAULT;
        continue;
      case INSIDE_MAX_PROBLEMS :
        try {
          this.maxProblems = Integer.parseInt(currentArg);
          if (this.maxProblems <= 0) {
            throw new InvalidInputException(this.bind("configure.maxProblems", currentArg)); //$NON-NLS-1$
          }
          this.options.put(CompilerOptions.OPTION_MaxProblemPerUnit, currentArg);
        } catch (NumberFormatException e) {
          throw new InvalidInputException(this.bind("configure.maxProblems", currentArg)); //$NON-NLS-1$
        }
        mode = DEFAULT;
        continue;
      case INSIDE_SOURCE :
        if (this.didSpecifySource) {
          throw new InvalidInputException(
            this.bind("configure.duplicateSource", currentArg));//$NON-NLS-1$
        }
        this.didSpecifySource = true;
        if (currentArg.equals("1.3")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
        } else if (currentArg.equals("1.4")) { //$NON-NLS-1$
          this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4);
        } else if (currentArg.equals("1.5") || currentArg.equals("5") || currentArg.equals("5.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
        } else if (currentArg.equals("1.6") || currentArg.equals("6") || currentArg.equals("6.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
        } else if (currentArg.equals("1.7") || currentArg.equals("7") || currentArg.equals("7.0")) { //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
          this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_7);
        } else {
          throw new InvalidInputException(this.bind("configure.source", currentArg)); //$NON-NLS-1$
        }
        mode = DEFAULT;
        continue;
      case INSIDE_DEFAULT_ENCODING :
        if (didSpecifyDefaultEncoding) {
          throw new InvalidInputException(
            this.bind("configure.duplicateDefaultEncoding", currentArg)); //$NON-NLS-1$
        }
        try { // ensure encoding is supported
          new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg);
        } catch (UnsupportedEncodingException e) {
          throw new InvalidInputException(
            this.bind("configure.unsupportedEncoding", currentArg)); //$NON-NLS-1$
        }
        this.options.put(CompilerOptions.OPTION_Encoding, currentArg);
        didSpecifyDefaultEncoding = true;
        mode = DEFAULT;
        continue;
      case INSIDE_DESTINATION_PATH :
        this.setDestinationPath(currentArg.equals(NONE) ? NONE : currentArg);
        mode = DEFAULT;
        continue;
      case INSIDE_CLASSPATH_start:
        mode = DEFAULT;
        index += processPaths(newCommandLineArgs, index, currentArg, classpaths);
        continue;
      case INSIDE_BOOTCLASSPATH_start:
        mode = DEFAULT;
        index += processPaths(newCommandLineArgs, index, currentArg, bootclasspaths);
        continue;
      case INSIDE_SOURCE_PATH_start:
        mode = DEFAULT;
        String[] sourcePaths = new String[1];
        index += processPaths(newCommandLineArgs, index, currentArg, sourcePaths);
        sourcepathClasspathArg = sourcePaths[0];
        continue;
      case INSIDE_EXT_DIRS:
        if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$
          throw new InvalidInputException(
            this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$
              "-extdir")); //$NON-NLS-1$
        }
        StringTokenizer tokenizer = new StringTokenizer(currentArg,  File.pathSeparator, false);
        extdirsClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
        while (tokenizer.hasMoreTokens())
          extdirsClasspaths.add(tokenizer.nextToken());
        mode = DEFAULT;
        continue;
      case INSIDE_ENDORSED_DIRS:
        if (currentArg.indexOf("[-d") != -1) { //$NON-NLS-1$
          throw new InvalidInputException(
            this.bind("configure.unexpectedDestinationPathEntry", //$NON-NLS-1$
              "-endorseddirs")); //$NON-NLS-1$
        }        tokenizer = new StringTokenizer(currentArg,  File.pathSeparator, false);
        endorsedDirClasspaths = new ArrayList(DEFAULT_SIZE_CLASSPATH);
        while (tokenizer.hasMoreTokens())
          endorsedDirClasspaths.add(tokenizer.nextToken());
        mode = DEFAULT;
        continue;
      case INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH:
        if (currentArg.endsWith("]")) { //$NON-NLS-1$
          customDestinationPath = currentArg.substring(0,
            currentArg.length() - 1);
        } else {
          throw new InvalidInputException(
            this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
              "[-d " + currentArg)); //$NON-NLS-1$
        }
        break;
      case INSIDE_PROCESSOR_PATH_start :
        // nothing to do here. This is consumed again by the AnnotationProcessorManager
        mode = DEFAULT;
        continue;
      case INSIDE_PROCESSOR_start :
        // nothing to do here. This is consumed again by the AnnotationProcessorManager
        mode = DEFAULT;
        continue;
      case INSIDE_S_start :
        // nothing to do here. This is consumed again by the AnnotationProcessorManager
        mode = DEFAULT;
        continue;
      case INSIDE_CLASS_NAMES :
        tokenizer = new StringTokenizer(currentArg, ","); //$NON-NLS-1$
        if (this.classNames == null) {
          this.classNames = new String[DEFAULT_SIZE_CLASSPATH];
        }
        while (tokenizer.hasMoreTokens()) {
          if (this.classNames.length == classCount) {
            // resize
            System.arraycopy(
              this.classNames,
              0,
              (this.classNames = new String[classCount * 2]),
              0,
              classCount);
          }
          this.classNames[classCount++] = tokenizer.nextToken();
        }
        mode = DEFAULT;
        continue;
    }

    // default is input directory, if no custom destination path exists
    // AspectJ Extension
    // see pr 60863.  All directories should have been dealt with at the AspectJ layer - if we have left
    // anything to be processed here it is an error.
    throw new InvalidInputException(
          "unrecognized single argument: \""+currentArg+"\"")
        /*
    if (customDestinationPath == null) {
      if (File.separatorChar != '/') {
        currentArg = currentArg.replace('/', File.separatorChar);
      }
      if (currentArg.endsWith("[-d")) { //$NON-NLS-1$
        currentSourceDirectory = currentArg.substring(0,
          currentArg.length() - 3);
        mode = INSIDE_SOURCE_DIRECTORY_DESTINATION_PATH;
        continue;
      } else {
        currentSourceDirectory = currentArg;
      }
    }
    File dir = new File(currentSourceDirectory);
    if (!dir.isDirectory()) {
      throw new InvalidInputException(
        this.bind("configure.unrecognizedOption", currentSourceDirectory)); //$NON-NLS-1$
    }
    String[] result = FileFinder.find(dir, SuffixConstants.SUFFIX_STRING_JAVA);
    if (NONE.equals(customDestinationPath)) {
      customDestinationPath = NONE; // ensure == comparison
    }
    if (this.filenames != null) {
      // some source files were specified explicitly
      int length = result.length;
      System.arraycopy(
        this.filenames,
        0,
        (this.filenames = new String[length + filesCount]),
        0,
        filesCount);
      System.arraycopy(
        this.encodings,
        0,
        (this.encodings = new String[length + filesCount]),
        0,
        filesCount);
      System.arraycopy(
        this.destinationPaths,
        0,
        (this.destinationPaths = new String[length + filesCount]),
        0,
        filesCount);
      System.arraycopy(result, 0, this.filenames, filesCount, length);
      for (int i = 0; i < length; i++) {
        this.encodings[filesCount + i] = customEncoding;
        this.destinationPaths[filesCount + i] = customDestinationPath;
      }
      filesCount += length;
      customEncoding = null;
      customDestinationPath = null;
      currentSourceDirectory = null;
    } else {
      this.filenames = result;
      filesCount = this.filenames.length;
      this.encodings = new String[filesCount];
      this.destinationPaths = new String[filesCount];
      for (int i = 0; i < filesCount; i++) {
        this.encodings[i] = customEncoding;
        this.destinationPaths[i] = customDestinationPath;
      }
      customEncoding = null;
      customDestinationPath = null;
      currentSourceDirectory = null;
    }
    mode = DEFAULT;
    continue;
    */ // End AspectJ Extensioin
  }

    // AspectJ Extension
    // old code:
    // if (printUsageRequired || (filesCount == 0 && classCount == 0)) {
    // new code:
  if (printUsageRequired || hasNoFiles(filesCount)) { // AspectJ Extension
    // End AspectJ Extension
      printUsage();
    if (usageSection ==  null) {
      printUsage(); // default
    } else {
      printUsage(usageSection);
    }
    this.proceed = false;
    return;
  }

  if (this.log != null) {
    this.logger.setLog(this.log);
  } else {
    this.showProgress = false;
  }
  this.logger.logVersion(printVersionRequired);

  validateOptions(didSpecifyCompliance);
 
  // Enable annotation processing by default in batch mode when compliance is at least 1.6
  // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=185768
  if (!didSpecifyDisabledAnnotationProcessing
      && CompilerOptions.versionToJdkLevel(this.options.get(CompilerOptions.OPTION_Compliance)) >= ClassFileConstants.JDK1_6) {
    this.options.put(CompilerOptions.OPTION_Process_Annotations, CompilerOptions.ENABLED);
  }

  this.logger.logCommandLineArguments(newCommandLineArgs);
  this.logger.logOptions(this.options);
  if (this.repetitions == 0) {
    this.repetitions = 1;
  }
  if (this.repetitions >= 3 && this.timing) {
    this.times = new long[this.repetitions];
    this.timesCounter = 0;
  }

  if (filesCount != 0) {
    System.arraycopy(
      this.filenames,
      0,
      (this.filenames = new String[filesCount]),
      0,
      filesCount);
  }

  if (classCount != 0) {
    System.arraycopy(
      this.classNames,
      0,
      (this.classNames = new String[classCount]),
      0,
      classCount);
  }
 
  setPaths(bootclasspaths,
      sourcepathClasspathArg,
      sourcepathClasspaths,
      classpaths,
      extdirsClasspaths,
      endorsedDirClasspaths,
      customEncoding);
}

protected void disableWarnings() {
  Object[] entries = this.options.entrySet().toArray();
  for (int i = 0, max = entries.length; i < max; i++) {
    Map.Entry entry = (Map.Entry) entries[i];
    if (!(entry.getKey() instanceof String))
      continue;
    if (!(entry.getValue() instanceof String))
      continue;
    if (((String) entry.getValue()).equals(CompilerOptions.WARNING)) {
      this.options.put(entry.getKey(), CompilerOptions.IGNORE);
    }
  }
  this.options.put(CompilerOptions.OPTION_TaskTags, Util.EMPTY_STRING);
}

public String extractDestinationPathFromSourceFile(CompilationResult result) {
  ICompilationUnit compilationUnit = result.compilationUnit;
  if (compilationUnit != null) {
    char[] fileName = compilationUnit.getFileName();
    int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
    if (lastIndex != -1) {
      final String outputPathName = new String(fileName, 0, lastIndex);
      final File output = new File(outputPathName);
      if (output.exists() && output.isDirectory()) {
        return outputPathName;
      }
    }
  }
  return System.getProperty("user.dir"); //$NON-NLS-1$
}

/*
* Answer the component to which will be handed back compilation results from the compiler
*/
public ICompilerRequestor getBatchRequestor() {
  return new ICompilerRequestor() {
    int lineDelta = 0;
    public void acceptResult(CompilationResult compilationResult) {
      if (compilationResult.lineSeparatorPositions != null) {
        int unitLineCount = compilationResult.lineSeparatorPositions.length;
        Main.this.lineCount += unitLineCount;
        this.lineDelta += unitLineCount;
        if (Main.this.showProgress && this.lineDelta > 2000) {
          // in -log mode, dump a dot every 2000 lines compiled
          Main.this.logger.logProgress();
          this.lineDelta = 0;
        }
      }
      Main.this.logger.startLoggingSource(compilationResult);
      if (compilationResult.hasProblems() || compilationResult.hasTasks()) {
        int localErrorCount = Main.this.logger.logProblems(compilationResult.getAllProblems(), compilationResult.compilationUnit.getContents(), Main.this);
        // exit?
        if (Main.this.systemExitWhenFinished && !Main.this.proceedOnError && (localErrorCount > 0)) {
          // ensure dumping problems for enqueued units as well, since may contain primary errors (123476)
          CompilationUnitDeclaration[] queuedUnits = Main.this.batchCompiler.unitsToProcess;
          for (int i = 0, length = Main.this.batchCompiler.totalUnits; i < length; i++) {
            CompilationUnitDeclaration queuedUnit = queuedUnits[i];
            if (queuedUnit == null) continue;
            CompilationResult result = queuedUnit.compilationResult;
            if (result.hasProblems() && !result.hasBeenAccepted) {
              Main.this.logger.logProblems(result.getAllProblems(), result.compilationUnit.getContents(), Main.this);
            }
          }
          Main.this.logger.endLoggingSource();
          Main.this.logger.endLoggingSources();
          Main.this.logger.printStats();
          Main.this.logger.flush();
          Main.this.logger.close();
          System.exit(-1);
        }
      }
      outputClassFiles(compilationResult);
      Main.this.logger.endLoggingSource();
    }
  };
}

/*
*  Build the set of compilation source units
*/
public CompilationUnit[] getCompilationUnits()
  throws InvalidInputException {
  int fileCount = this.filenames.length;
  CompilationUnit[] units = new CompilationUnit[fileCount];
  HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);

  String defaultEncoding = (String) this.options.get(CompilerOptions.OPTION_Encoding);
  if (Util.EMPTY_STRING.equals(defaultEncoding))
    defaultEncoding = null;

  for (int i = 0; i < fileCount; i++) {
    char[] charName = this.filenames[i].toCharArray();
    if (knownFileNames.get(charName) != null)
      throw new InvalidInputException(this.bind("unit.more", this.filenames[i])); //$NON-NLS-1$
    knownFileNames.put(charName, charName);
    File file = new File(this.filenames[i]);
    if (!file.exists())
      throw new InvalidInputException(this.bind("unit.missing", this.filenames[i])); //$NON-NLS-1$
    String encoding = this.encodings[i];
    if (encoding == null)
      encoding = defaultEncoding;
    units[i] = new CompilationUnit(null, this.filenames[i], encoding,
        this.destinationPaths[i]);
  }
  return units;
}

/*
*  Low-level API performing the actual compilation
*/
public IErrorHandlingPolicy getHandlingPolicy() {

  // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
  return new IErrorHandlingPolicy() {
    public boolean proceedOnErrors() {
      return Main.this.proceedOnError; // stop if there are some errors
    }
    public boolean stopOnFirstError() {
      return false;
    }
  };
}
/*
* External API
*/
public File getJavaHome() {
  if (!javaHomeChecked) {
    javaHomeChecked = true;
    String javaHome = System.getProperty("java.home");//$NON-NLS-1$
    if (javaHome != null) {
      this.javaHomeCache = new File(javaHome);
      if (!this.javaHomeCache.exists())
        this.javaHomeCache = null;
    }
  }
  return this.javaHomeCache;
}

public FileSystem getLibraryAccess() {
  return new FileSystem(this.checkedClasspaths, this.filenames);
}

/*
*  Low-level API performing the actual compilation
*/
public IProblemFactory getProblemFactory() {
  return new DefaultProblemFactory(this.compilerLocale);
}
/*
* External API
*/
protected void initialize(PrintWriter outWriter,
    PrintWriter errWriter,
    boolean systemExit) {
  this.initialize(outWriter, errWriter, systemExit, null);
}
protected void initialize(PrintWriter outWriter,
    PrintWriter errWriter,
    boolean systemExit,
    Map customDefaultOptions) {
  this.logger = new Logger(this, outWriter, errWriter);
  this.proceed = true;
  this.out = outWriter;
  this.err = errWriter;
  this.systemExitWhenFinished = systemExit;
  this.options = new CompilerOptions().getMap();
  if (customDefaultOptions != null) {
    this.didSpecifySource = customDefaultOptions.get(CompilerOptions.OPTION_Source) != null;
    this.didSpecifyTarget = customDefaultOptions.get(CompilerOptions.OPTION_TargetPlatform) != null;
    for (Iterator iter = customDefaultOptions.entrySet().iterator(); iter.hasNext();) {
      Map.Entry entry = (Map.Entry) iter.next();
      this.options.put(entry.getKey(), entry.getValue());
    }
  } else {
    this.didSpecifySource = false;
    this.didSpecifyTarget = false;
  }
  this.classNames = null;
}
// Dump classfiles onto disk for all compilation units that where successful
// and do not carry a -d none spec, either directly or inherited from Main.
public void outputClassFiles(CompilationResult unitResult) {
  if (!((unitResult == null) || (unitResult.hasErrors() && !this.proceedOnError))) {
    ClassFile[] classFiles = unitResult.getClassFiles();
    String currentDestinationPath = null;
    boolean generateClasspathStructure = false;
    CompilationUnit compilationUnit =
      (CompilationUnit) unitResult.compilationUnit;
    if (compilationUnit.destinationPath == null) {
      if (this.destinationPath == null) {
        currentDestinationPath =
          extractDestinationPathFromSourceFile(unitResult);
      } else if (this.destinationPath != NONE) {
        currentDestinationPath = this.destinationPath;
        generateClasspathStructure = true;
      } // else leave currentDestinationPath null
    } else if (compilationUnit.destinationPath != NONE) {
      currentDestinationPath = compilationUnit.destinationPath;
      generateClasspathStructure = true;
    } // else leave currentDestinationPath null
    if (currentDestinationPath != null) {
      for (int i = 0, fileCount = classFiles.length; i < fileCount; i++) {
        // retrieve the key and the corresponding classfile
        ClassFile classFile = classFiles[i];
        char[] filename = classFile.fileName();
        int length = filename.length;
        char[] relativeName = new char[length + 6];
        System.arraycopy(filename, 0, relativeName, 0, length);
        System.arraycopy(SuffixConstants.SUFFIX_class, 0, relativeName, length, 6);
        CharOperation.replace(relativeName, '/', File.separatorChar);
        String relativeStringName = new String(relativeName);
        try {
          if (this.compilerOptions.verbose)
            this.out.println(
              Messages.bind(
                Messages.compilation_write,
                new String[] {
                  String.valueOf(this.exportedClassFilesCounter+1),
                  relativeStringName
                }));
          ClassFile.writeToDisk(
            generateClasspathStructure,
            currentDestinationPath,
            relativeStringName,
            classFile);
          LookupEnvironment env = this.batchCompiler.lookupEnvironment;
          if (classFile.isShared) env.classFilePool.release(classFile);
          this.logger.logClassFile(
            generateClasspathStructure,
            currentDestinationPath,
            relativeStringName);
          this.exportedClassFilesCounter++;
        } catch (IOException e) {
          this.logger.logNoClassFileCreated(currentDestinationPath, relativeStringName, e);
        }
      }
    }
  }
}

/*
*  Low-level API performing the actual compilation
*/
public void performCompilation() throws InvalidInputException {

  this.startTime = System.currentTimeMillis();

  FileSystem environment = getLibraryAccess();
  this.compilerOptions = new CompilerOptions(this.options);
  this.compilerOptions.performMethodsFullRecovery = false;
  this.compilerOptions.performStatementsRecovery = false;
  this.batchCompiler =
    new Compiler(
      environment,
      getHandlingPolicy(),
      this.compilerOptions,
      getBatchRequestor(),
      getProblemFactory(),
      this.out);

  if (this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_6
      && this.compilerOptions.processAnnotations) {
    if (checkVMVersion(ClassFileConstants.JDK1_6)) {
      initializeAnnotationProcessorManager();
      if (this.classNames != null) {
        this.batchCompiler.setBinaryTypes(processClassNames(this.batchCompiler.lookupEnvironment));
      }
    } else {
      // report a warning
      this.logger.logIncorrectVMVersionForAnnotationProcessing();
    }
  }

  // set the non-externally configurable options.
  this.compilerOptions.verbose = this.verbose;
  this.compilerOptions.produceReferenceInfo = this.produceRefInfo;
  try {
    this.logger.startLoggingSources();
    this.batchCompiler.compile(getCompilationUnits());
  } finally {
    this.logger.endLoggingSources();
  }

  if (this.extraProblems != null) {
    this.logger.loggingExtraProblems(this);
    this.extraProblems = null;
  }
  this.logger.printStats();

  // cleanup
  environment.cleanup();
}
private ReferenceBinding[] processClassNames(LookupEnvironment environment) throws InvalidInputException {
  // check for .class file presence in case of apt processing
  int length = this.classNames.length;
  ReferenceBinding[] referenceBindings = new ReferenceBinding[length];
  for (int i = 0; i < length; i++) {
    String currentName = this.classNames[i];
    char[][] compoundName = null;
    if (currentName.indexOf('.') != -1) {
      // consider names with '.' as fully qualified names
      char[] typeName = currentName.toCharArray();
      compoundName = CharOperation.splitOn('.', typeName);
    } else {
      compoundName = new char[][] { currentName.toCharArray() };
    }
    ReferenceBinding type = environment.getType(compoundName);
    if (type != null && type.isValidBinding()) {
      if (type.isBinaryBinding()) {
        referenceBindings[i] = type;
      }
    } else {
      throw new InvalidInputException(
          this.bind("configure.invalidClassName", currentName));//$NON-NLS-1$
    }
  }
  return referenceBindings;
}
protected void initializeAnnotationProcessorManager() {
  try {
    Class c = Class.forName("org.aspectj.org.eclipse.jdt.internal.compiler.apt.dispatch.BatchAnnotationProcessorManager"); //$NON-NLS-1$
    AbstractAnnotationProcessorManager annotationManager = (AbstractAnnotationProcessorManager) c.newInstance();
    annotationManager.configure(this, this.expandedCommandLine);
    annotationManager.setErr(this.err);
    annotationManager.setOut(this.out);
    this.batchCompiler.annotationProcessorManager = annotationManager;
  } catch (ClassNotFoundException e) {
    // ignore
  } catch (InstantiationException e) {
    // should not happen
    throw new org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation();
  } catch (IllegalAccessException e) {
    // should not happen
    throw new org.aspectj.org.eclipse.jdt.internal.compiler.problem.AbortCompilation();
  } catch(UnsupportedClassVersionError e) {
    // report a warning
    this.logger.logIncorrectVMVersionForAnnotationProcessing();
  }
}
public void printUsage() {
  printUsage("misc.usage"); //$NON-NLS-1$
}
private void printUsage(String sectionID) {
  this.logger.logUsage(
    this.bind(
      sectionID,
      new String[] {
        System.getProperty("path.separator"), //$NON-NLS-1$
        this.bind("compiler.name"), //$NON-NLS-1$
        this.bind("compiler.version"), //$NON-NLS-1$
        this.bind("compiler.copyright") //$NON-NLS-1$
      }));
  this.logger.flush();
}
/*
* External API
*/
public void processPathEntries(final int defaultSize, final ArrayList paths,
      final String currentPath, String customEncoding, boolean isSourceOnly,
      boolean rejectDestinationPathOnJars)
    throws InvalidInputException {
  String currentClasspathName = null;
  String currentDestinationPath = null;
  ArrayList currentRuleSpecs = new ArrayList(defaultSize);
  StringTokenizer tokenizer = new StringTokenizer(currentPath,
      File.pathSeparator + "[]", true); //$NON-NLS-1$
  ArrayList tokens = new ArrayList();
  while (tokenizer.hasMoreTokens()) {
    tokens.add(tokenizer.nextToken());
  }
  // state machine
  final int start = 0;
  final int readyToClose = 1;
  // 'path' 'path1[rule];path2'
  final int readyToCloseEndingWithRules = 2;
  // 'path[rule]' 'path1;path2[rule]'
  final int readyToCloseOrOtherEntry = 3;
  // 'path[rule];' 'path;' 'path1;path2;'
  final int rulesNeedAnotherRule = 4;
  // 'path[rule1;'
  final int rulesStart = 5;
  // 'path[' 'path1;path2['
  final int rulesReadyToClose = 6;
  // 'path[rule' 'path[rule1;rule2'
  final int destinationPathReadyToClose = 7;
  // 'path[-d bin'
  final int readyToCloseEndingWithDestinationPath = 8;
  // 'path[-d bin]' 'path[rule][-d bin]'
  final int destinationPathStart = 9;
  // 'path[rule]['
  final int bracketOpened = 10;
  // '.*[.*'
  final int bracketClosed = 11;
  // '.*([.*])+'

  final int error = 99;
  int state = start;
  String token = null;
  int cursor = 0, tokensNb = tokens.size(), bracket = -1;
  while (cursor < tokensNb && state != error) {
    token = (String) tokens.get(cursor++);
    if (token.equals(File.pathSeparator)) {
      switch (state) {
      case start:
      case readyToCloseOrOtherEntry:
      case bracketOpened:
        break;
      case readyToClose:
      case readyToCloseEndingWithRules:
      case readyToCloseEndingWithDestinationPath:
        state = readyToCloseOrOtherEntry;
        addNewEntry(paths, currentClasspathName, currentRuleSpecs,
            customEncoding, currentDestinationPath, isSourceOnly,
            rejectDestinationPathOnJars);
        currentRuleSpecs.clear();
        break;
      case rulesReadyToClose:
        state = rulesNeedAnotherRule;
        break;
      case destinationPathReadyToClose:
        throw new InvalidInputException(
          this.bind("configure.incorrectDestinationPathEntry", //$NON-NLS-1$
            currentPath));
      case bracketClosed:
        cursor = bracket + 1;
        state = rulesStart;
        break;
      default:
        state = error;
      }
    } else if (token.equals("[")) { //$NON-NLS-1$
      switch (state) {
      case start:
        currentClasspathName = ""; //$NON-NLS-1$
      case readyToClose:
        bracket = cursor - 1;
      case bracketClosed:
        state = bracketOpened;
        break;
      case readyToCloseEndingWithRules:
        state = destinationPathStart;
        break;
      case readyToCloseEndingWithDestinationPath:
        state = rulesStart;
        break;
      case bracketOpened:
      default:
        state = error;
      }
    } else if (token.equals("]")) { //$NON-NLS-1$
      switch (state) {
      case rulesReadyToClose:
        state = readyToCloseEndingWithRules;
        break;
      case destinationPathReadyToClose:
        state = readyToCloseEndingWithDestinationPath;
        break;
      case bracketOpened:
        state = bracketClosed;
        break;
      case bracketClosed:
      default:
        state = error;
      }
    } else {
      // regular word
      switch (state) {
      case start:
      case readyToCloseOrOtherEntry:
        state = readyToClose;
        currentClasspathName = token;
        break;
      case rulesStart:
        if (token.startsWith("-d ")) { //$NON-NLS-1$
          if (currentDestinationPath != null) {
            throw new InvalidInputException(
                this.bind("configure.duplicateDestinationPathEntry", //$NON-NLS-1$
                    currentPath));
          }
          currentDestinationPath = token.substring(3).trim();
          state = destinationPathReadyToClose;
          break;
        } // else we proceed with a rule
      case rulesNeedAnotherRule:
        if (currentDestinationPath != null) {
          throw new InvalidInputException(
              this.bind("configure.accessRuleAfterDestinationPath", //$NON-NLS-1$
                currentPath));
        }
        state = rulesReadyToClose;
        currentRuleSpecs.add(token);
        break;
      case destinationPathStart:
        if (!token.startsWith("-d ")) { //$NON-NLS-1$
          state = error;
        } else {
          currentDestinationPath = token.substring(3).trim();
          state = destinationPathReadyToClose;
        }
        break;
      case bracketClosed:
        for (int i = bracket; i < cursor ; i++) {
          currentClasspathName += (String) tokens.get(i);
        }
        state = readyToClose;
        break;
      case bracketOpened:
        break;
      default:
        state = error;
      }
    }
    if (state == bracketClosed && cursor == tokensNb) {
      cursor = bracket + 1;
      state = rulesStart;
    }
  }
  switch(state) {
    case readyToCloseOrOtherEntry:
      break;
    case readyToClose:
    case readyToCloseEndingWithRules:
    case readyToCloseEndingWithDestinationPath:
      addNewEntry(paths, currentClasspathName, currentRuleSpecs,
        customEncoding, currentDestinationPath, isSourceOnly,
        rejectDestinationPathOnJars);
      break;
    case bracketOpened:
    case bracketClosed:
    default :
      // we go on anyway
      if (currentPath.length() != 0) {
        this.logger.logIncorrectClasspath(currentPath);
      }
  }
}

private int processPaths(String[] args, int index, String currentArg, ArrayList paths) throws InvalidInputException {
  int localIndex = index;
  int count = 0;
  for (int i = 0, max = currentArg.length(); i < max; i++) {
    switch(currentArg.charAt(i)) {
      case '[' :
        count++;
        break;
      case ']' :
        count--;
        break;
    }
  }
  if (count == 0) {
    paths.add(currentArg);
  } else if (count > 1) {
    throw new InvalidInputException(
        this.bind("configure.unexpectedBracket", //$NON-NLS-1$
              currentArg));
  } else {
    StringBuffer currentPath = new StringBuffer(currentArg);
    while (true) {
        if (localIndex >= args.length) {
          throw new InvalidInputException(
              this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                    currentArg));
        }
        localIndex++;
        String nextArg = args[localIndex];
        for (int i = 0, max = nextArg.length(); i < max; i++) {
          switch(nextArg.charAt(i)) {
            case '[' :
              if (count > 1) {
                throw new InvalidInputException(
                    this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                          nextArg));
              }
              count++;
              break;
            case ']' :
              count--;
              break;
          }
        }
        if (count == 0) {
          currentPath.append(' ');
          currentPath.append(nextArg);
          paths.add(currentPath.toString());
          return localIndex - index;
        } else if (count < 0) {
        throw new InvalidInputException(
            this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                  nextArg));
      } else {
        currentPath.append(' ');
        currentPath.append(nextArg);
      }
    }

  }
  return localIndex - index;
}

    // AspectJ Extension
  // For AspectJ we handle files in a separate arg parser, in the future make this a protected method for extension
  private boolean hasNoFiles(int filesCount) {
    return false;
  }
  // End AspectJ Extension
 
private int processPaths(String[] args, int index, String currentArg, String[] paths) throws InvalidInputException {
  int localIndex = index;
  int count = 0;
  for (int i = 0, max = currentArg.length(); i < max; i++) {
    switch(currentArg.charAt(i)) {
      case '[' :
        count++;
        break;
      case ']' :
        count--;
        break;
    }
  }
  if (count == 0) {
    paths[0] = currentArg;
  } else {
    StringBuffer currentPath = new StringBuffer(currentArg);
    while (true) {
        localIndex++;
        if (localIndex >= args.length) {
          throw new InvalidInputException(
              this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                    currentArg));
        }
        String nextArg = args[localIndex];
        for (int i = 0, max = nextArg.length(); i < max; i++) {
          switch(nextArg.charAt(i)) {
            case '[' :
              if (count > 1) {
                throw new InvalidInputException(
                    this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                          currentArg));
              }
              count++;
              break;
            case ']' :
              count--;
              break;
          }
        }
        if (count == 0) {
          currentPath.append(' ');
          currentPath.append(nextArg);
          paths[0] = currentPath.toString();
          return localIndex - index;
        } else if (count < 0) {
        throw new InvalidInputException(
            this.bind("configure.unexpectedBracket", //$NON-NLS-1$
                  currentArg));
      } else {
        currentPath.append(' ');
        currentPath.append(nextArg);
      }
    }

  }
  return localIndex - index;
}
/**
* Creates a NLS catalog for the given locale.
*/
public void relocalize() {
  relocalize(Locale.getDefault());
}

private void relocalize(Locale locale) {
  this.compilerLocale = locale;
  try {
    this.bundle = ResourceBundleFactory.getBundle(locale);
  } catch(MissingResourceException e) {
    System.out.println("Missing resource : " + Main.bundleName.replace('.', '/') + ".properties for locale " + locale); //$NON-NLS-1$//$NON-NLS-2$
    throw e;
  }
}
/*
* External API
*/
public void setLocale(Locale locale) {
  relocalize(locale);
}
/*
* External API
*/
public void setDestinationPath(String dest) {
  this.destinationPath = dest;
}
/*
* External API
*/
protected void setPaths(ArrayList bootclasspaths,
    String sourcepathClasspathArg,
    ArrayList sourcepathClasspaths,
    ArrayList classpaths,
    ArrayList extdirsClasspaths,
    ArrayList endorsedDirClasspaths,
    String customEncoding) throws InvalidInputException {

  // process bootclasspath, classpath and sourcepaths
   bootclasspaths = handleBootclasspath(bootclasspaths, customEncoding);

  classpaths = handleClasspath(classpaths, customEncoding);

  if (sourcepathClasspathArg != null) {
    processPathEntries(DEFAULT_SIZE_CLASSPATH, sourcepathClasspaths,
      sourcepathClasspathArg, customEncoding, true, false);
  }

  /*
   * Feed endorsedDirClasspath according to:
   * - -extdirs first if present;
   * - else java.ext.dirs if defined;
   * - else default extensions directory for the platform.
   */
  extdirsClasspaths = handleExtdirs(extdirsClasspaths);

  endorsedDirClasspaths = handleEndorseddirs(endorsedDirClasspaths);

  /*
   * Concatenate classpath entries
   * We put the bootclasspath at the beginning of the classpath
   * entries, followed by the extension libraries, followed by
   * the sourcepath followed by the classpath.  All classpath
   * entries are searched for both sources and binaries except
   * the sourcepath entries which are searched for sources only.
   */
  bootclasspaths.addAll(endorsedDirClasspaths);
  bootclasspaths.addAll(extdirsClasspaths);
  bootclasspaths.addAll(sourcepathClasspaths);
  bootclasspaths.addAll(classpaths);
  classpaths = bootclasspaths;
  classpaths = FileSystem.ClasspathNormalizer.normalize(classpaths);
  this.checkedClasspaths = new FileSystem.Classpath[classpaths.size()];
  classpaths.toArray(this.checkedClasspaths);
  this.logger.logClasspath(this.checkedClasspaths);
}
protected void validateOptions(boolean didSpecifyCompliance) throws InvalidInputException {
  if (didSpecifyCompliance) {
    Object version = this.options.get(CompilerOptions.OPTION_Compliance);
    if (CompilerOptions.VERSION_1_3.equals(version)) {
      if (!this.didSpecifySource) this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
      if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
    } else if (CompilerOptions.VERSION_1_4.equals(version)) {
      if (this.didSpecifySource) {
        Object source = this.options.get(CompilerOptions.OPTION_Source);
        if (CompilerOptions.VERSION_1_3.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
        } else if (CompilerOptions.VERSION_1_4.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
        }
      } else {
        this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
        if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
      }
    } else if (CompilerOptions.VERSION_1_5.equals(version)) {
      if (this.didSpecifySource) {
        Object source = this.options.get(CompilerOptions.OPTION_Source);
        if (CompilerOptions.VERSION_1_3.equals(source)
            || CompilerOptions.VERSION_1_4.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
        } else if (CompilerOptions.VERSION_1_5.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
        }
      } else {
        this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_5);
        if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
      }
    } else if (CompilerOptions.VERSION_1_6.equals(version)) {
      if (this.didSpecifySource) {
        Object source = this.options.get(CompilerOptions.OPTION_Source);
        if (CompilerOptions.VERSION_1_3.equals(source)
            || CompilerOptions.VERSION_1_4.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
        } else if (CompilerOptions.VERSION_1_5.equals(source)
            || CompilerOptions.VERSION_1_6.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
        }
      } else {
        this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
        if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
      }
    } else if (CompilerOptions.VERSION_1_7.equals(version)) {
      if (this.didSpecifySource) {
        Object source = this.options.get(CompilerOptions.OPTION_Source);
        if (CompilerOptions.VERSION_1_3.equals(source)
            || CompilerOptions.VERSION_1_4.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
        } else if (CompilerOptions.VERSION_1_5.equals(source)
            || CompilerOptions.VERSION_1_6.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
        } else if (CompilerOptions.VERSION_1_7.equals(source)) {
          if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
        }
      } else {
        this.options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_7);
        if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
      }
    }
  } else if (this.didSpecifySource) {
    Object version = this.options.get(CompilerOptions.OPTION_Source);
    // default is source 1.3 target 1.2 and compliance 1.4
    if (CompilerOptions.VERSION_1_4.equals(version)) {
      if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
      if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
    } else if (CompilerOptions.VERSION_1_5.equals(version)) {
      if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_5);
      if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_5);
    } else if (CompilerOptions.VERSION_1_6.equals(version)) {
      if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6);
      if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_6);
    } else if (CompilerOptions.VERSION_1_7.equals(version)) {
      if (!didSpecifyCompliance) this.options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_7);
      if (!this.didSpecifyTarget) this.options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_7);
    }
  }

  final Object sourceVersion = this.options.get(CompilerOptions.OPTION_Source);
  final Object compliance = this.options.get(CompilerOptions.OPTION_Compliance);
  if (sourceVersion.equals(CompilerOptions.VERSION_1_7)
      && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_7) {
    // compliance must be 1.7 if source is 1.7
    throw new InvalidInputException(this.bind("configure.incompatibleComplianceForSource", (String)this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_7)); //$NON-NLS-1$
  } else if (sourceVersion.equals(CompilerOptions.VERSION_1_6)
      && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_6) {
    // compliance must be 1.6 if source is 1.6
    throw new InvalidInputException(this.bind("configure.incompatibleComplianceForSource", (String)this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_6)); //$NON-NLS-1$
  } else if (sourceVersion.equals(CompilerOptions.VERSION_1_5)
      && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_5) {
    // compliance must be 1.5 if source is 1.5
    throw new InvalidInputException(this.bind("configure.incompatibleComplianceForSource", (String)this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_5)); //$NON-NLS-1$
  } else if (sourceVersion.equals(CompilerOptions.VERSION_1_4)
      && CompilerOptions.versionToJdkLevel(compliance) < ClassFileConstants.JDK1_4) {
    // compliance must be 1.4 if source is 1.4
    throw new InvalidInputException(this.bind("configure.incompatibleComplianceForSource", (String)this.options.get(CompilerOptions.OPTION_Compliance), CompilerOptions.VERSION_1_4)); //$NON-NLS-1$
  }

  // check and set compliance/source/target compatibilities
  if (this.didSpecifyTarget) {
    final Object targetVersion = this.options.get(CompilerOptions.OPTION_TargetPlatform);
    // tolerate jsr14 target
    if (CompilerOptions.VERSION_JSR14.equals(targetVersion)) {
      // expecting source >= 1.5
      if (CompilerOptions.versionToJdkLevel(sourceVersion) < ClassFileConstants.JDK1_5) {
        throw new InvalidInputException(this.bind("configure.incompatibleTargetForGenericSource", (String) targetVersion, (String) sourceVersion)); //$NON-NLS-1$
      }
    } else {
      // target must be 1.7 if source is 1.7
      if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_7
          && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_7){
        throw new InvalidInputException(this.bind("configure.incompatibleTargetForSource", (String) targetVersion, CompilerOptions.VERSION_1_7)); //$NON-NLS-1$
      }
      // target must be 1.6 if source is 1.6
      if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_6
          && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_6){
        throw new InvalidInputException(this.bind("configure.incompatibleTargetForSource", (String) targetVersion, CompilerOptions.VERSION_1_6)); //$NON-NLS-1$
      }
      // target must be 1.5 if source is 1.5
      if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_5
          && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_5){
        throw new InvalidInputException(this.bind("configure.incompatibleTargetForSource", (String) targetVersion, CompilerOptions.VERSION_1_5)); //$NON-NLS-1$
      }
      // target must be 1.4 if source is 1.4
      if (CompilerOptions.versionToJdkLevel(sourceVersion) >= ClassFileConstants.JDK1_4
          && CompilerOptions.versionToJdkLevel(targetVersion) < ClassFileConstants.JDK1_4){
        throw new InvalidInputException(this.bind("configure.incompatibleTargetForSource", (String) targetVersion, CompilerOptions.VERSION_1_4)); //$NON-NLS-1$
      }
      // target cannot be greater than compliance level
      if (CompilerOptions.versionToJdkLevel(compliance) < CompilerOptions.versionToJdkLevel(targetVersion)){
        throw new InvalidInputException(this.bind("configure.incompatibleComplianceForTarget", (String)this.options.get(CompilerOptions.OPTION_Compliance), (String) targetVersion)); //$NON-NLS-1$
      }
    }
  }
}
}
TOP

Related Classes of org.aspectj.org.eclipse.jdt.internal.compiler.batch.Main$Logger

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
>
  • org.aspectj.org.eclipse.jdt.internal.compiler.ICompilerRequestor
  • TOP
    Copyright © 2018 www.massapi.com. All rights reserved.
    All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.