/******************************************************************************* * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v0.5 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v05.html * * Contributors: * IBM Corporation - initial API and implementation ******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.batch; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.StringTokenizer; import net.sourceforge.phpdt.core.compiler.IProblem; import net.sourceforge.phpdt.core.compiler.InvalidInputException; import net.sourceforge.phpdt.internal.compiler.ClassFile; import net.sourceforge.phpdt.internal.compiler.CompilationResult; import net.sourceforge.phpdt.internal.compiler.Compiler; import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor; import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy; import net.sourceforge.phpdt.internal.compiler.IProblemFactory; import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit; import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions; import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblem; import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory; import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities; import net.sourceforge.phpdt.internal.compiler.util.CharOperation; import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject; public class Main implements ProblemSeverities { public boolean noWarn = false; public PrintWriter out; public boolean systemExitWhenFinished = true; public boolean proceedOnError = false; public boolean verbose = false; public boolean produceRefInfo = false; public boolean timer = false; public boolean showProgress = false; public long time = 0; public long lineCount; public boolean generatePackagesStructure; public Hashtable options; public String[] filenames; public String[] encodings; public String[] classpaths; public String destinationPath; public String log; public int repetitions; public int globalProblemsCount; public int globalErrorsCount; public int globalWarningsCount; public int exportedClassFilesCounter; public static final char[] CLASS_FILE_EXTENSION = ".class".toCharArray(); //$NON-NLS-1$ public final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$ public final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$ /* Bundle containing messages */ public static ResourceBundle bundle; public final static String bundleName = "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$ static { relocalize(); } public boolean proceed = true; public Main(PrintWriter writer, boolean systemExitWhenFinished) { this.out = writer; this.systemExitWhenFinished = systemExitWhenFinished; exportedClassFilesCounter = 0; options = new Hashtable(); options.put( CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); options.put( CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); options.put( CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.DO_NOT_GENERATE); options.put( CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.OPTIMIZE_OUT); options.put( CompilerOptions.OPTION_ReportUnreachableCode, CompilerOptions.ERROR); options.put(CompilerOptions.OPTION_ReportInvalidImport, CompilerOptions.ERROR); options.put( CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, CompilerOptions.WARNING); options.put( CompilerOptions.OPTION_ReportMethodWithConstructorName, CompilerOptions.WARNING); options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); options.put( CompilerOptions.OPTION_ReportHiddenCatchBlock, CompilerOptions.WARNING); options.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportAssertIdentifier, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3); options.put( CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); options.put( CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); } /* * Low-level API performing the actual compilation */ public boolean compile(String[] argv) { // decode command line arguments try { configure(argv); if (proceed) { if (showProgress) out.print(Main.bind("progress.compiling")); //$NON-NLS-1$ for (int i = 0; i < repetitions; i++) { globalProblemsCount = 0; globalErrorsCount = 0; globalWarningsCount = 0; lineCount = 0; if (repetitions > 1) { out.flush(); out.println( Main.bind( "compile.repetition", //$NON-NLS-1$ String.valueOf(i + 1), String.valueOf(repetitions))); } long startTime = System.currentTimeMillis(); // request compilation performCompilation(); if (timer) { time = System.currentTimeMillis() - startTime; if (lineCount != 0) { out.println( 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 { out.println(Main.bind("compile.totalTime", String.valueOf(time))); //$NON-NLS-1$ } } if (globalProblemsCount > 0) { if (globalProblemsCount == 1) { out.print(Main.bind("compile.oneProblem")); //$NON-NLS-1$ } else { out.print( Main.bind("compile.severalProblems", String.valueOf(globalProblemsCount))); //$NON-NLS-1$ } out.print(" ("); //$NON-NLS-1$ if (globalErrorsCount > 0) { if (globalErrorsCount == 1) { out.print(Main.bind("compile.oneError")); //$NON-NLS-1$ } else { out.print( Main.bind("compile.severalErrors", String.valueOf(globalErrorsCount))); //$NON-NLS-1$ } } if (globalWarningsCount > 0) { if (globalErrorsCount > 0) { out.print(", "); //$NON-NLS-1$ } if (globalWarningsCount == 1) { out.print(Main.bind("compile.oneWarning")); //$NON-NLS-1$ } else { out.print( Main.bind("compile.severalWarnings", String.valueOf(globalWarningsCount))); //$NON-NLS-1$ } } out.println(")"); //$NON-NLS-1$ } if (exportedClassFilesCounter != 0 && (this.showProgress || this.timer || this.verbose)) { if (exportedClassFilesCounter == 1) { out.print(Main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$ } else { out.print( Main.bind( "compile.severalClassFilesGenerated", //$NON-NLS-1$ String.valueOf(exportedClassFilesCounter))); } } } if (showProgress) System.out.println(); } if (systemExitWhenFinished) { out.flush(); System.exit(globalErrorsCount > 0 ? -1 : 0); } } catch (InvalidInputException e) { out.println(e.getMessage()); out.println("------------------------"); //$NON-NLS-1$ printUsage(); if (systemExitWhenFinished) { System.exit(-1); } } catch (ThreadDeath e) { // do not stop this one throw e; } catch (Throwable e) { // internal compiler error if (systemExitWhenFinished) { out.flush(); if (this.log != null) { out.close(); } System.exit(-1); } //e.printStackTrace(); } finally { out.flush(); if (this.log != null) { out.close(); } } if (globalErrorsCount == 0){ return true; } else { return false; } } /* * Internal IDE API */ public static boolean compile(String commandLine) { return compile(commandLine, new PrintWriter(System.out)); } /* * Internal IDE API for test harness purpose */ public static boolean compile(String commandLine, PrintWriter writer) { return new Main(writer, false).compile(tokenize(commandLine)); } 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 = "", lastToken; //$NON-NLS-1$ 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()) { lastToken = token; 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) { //$NON-NLS-1$ if (count == arguments.length) System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count); arguments[count++] = ""; //$NON-NLS-1$ } 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); arguments[count++] = token; } } startNewToken = false; } } System.arraycopy(arguments, 0, arguments = new String[count], 0, count); return arguments; } /* Decode the command line arguments */ public void configure(String[] argv) throws InvalidInputException { if ((argv == null) || (argv.length == 0)) throw new InvalidInputException(Main.bind("configure.noSourceFile")); //$NON-NLS-1$ final int InsideClasspath = 1; final int InsideDestinationPath = 2; final int TargetSetting = 4; final int InsideLog = 8; final int InsideRepetition = 16; final int InsideSource = 32; final int InsideDefaultEncoding = 64; final int Default = 0; int DEFAULT_SIZE_CLASSPATH = 4; boolean warnOptionInUse = false; boolean noWarnOptionInUse = false; int pathCount = 0; int index = -1, filesCount = 0, argCount = argv.length; int mode = Default; repetitions = 0; boolean versionIDRequired = false; boolean printUsageRequired = false; boolean didSpecifyCompliance = false; boolean didSpecifySourceLevel = false; boolean didSpecifyDefaultEncoding = false; boolean didSpecifyTarget = false; String customEncoding = null; String currentArg = ""; //$NON-NLS-1$ while (++index < argCount) { if (customEncoding != null) { throw new InvalidInputException( Main.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$ } currentArg = argv[index].trim(); customEncoding = null; if (currentArg.endsWith("]")) { //$NON-NLS-1$ // look for encoding specification int encodingStart = currentArg.indexOf('[') + 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( Main.bind("configure.unsupportedEncoding", customEncoding)); //$NON-NLS-1$ } } currentArg = currentArg.substring(0, encodingStart - 1); } } if (currentArg.endsWith(".java")) { //$NON-NLS-1$ if (filenames == null) { filenames = new String[argCount - index]; encodings = new String[argCount - index]; } else if (filesCount == filenames.length) { int length = filenames.length; System.arraycopy( filenames, 0, (filenames = new String[length + argCount - index]), 0, length); System.arraycopy( encodings, 0, (encodings = new String[length + argCount - index]), 0, length); } filenames[filesCount] = currentArg; encodings[filesCount++] = customEncoding; customEncoding = null; mode = Default; continue; } if (currentArg.equals("-log")) { //$NON-NLS-1$ if (log != null) throw new InvalidInputException( Main.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$ mode = InsideLog; continue; } if (currentArg.equals("-repeat")) { //$NON-NLS-1$ if (repetitions > 0) throw new InvalidInputException( Main.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$ mode = InsideRepetition; continue; } if (currentArg.equals("-source")) { //$NON-NLS-1$ mode = InsideSource; didSpecifySourceLevel = true; continue; } if (currentArg.equals("-encoding")) { //$NON-NLS-1$ mode = InsideDefaultEncoding; continue; } if (currentArg.equals("-1.3")) { //$NON-NLS-1$ if (didSpecifyCompliance) { throw new InvalidInputException( Main.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$ } didSpecifyCompliance = true; 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( Main.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$ } didSpecifyCompliance = true; options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); mode = Default; continue; } if (currentArg.equals("-d")) { //$NON-NLS-1$ if (destinationPath != null) throw new InvalidInputException( Main.bind("configure.duplicateOutputPath", currentArg)); //$NON-NLS-1$ mode = InsideDestinationPath; generatePackagesStructure = true; continue; } if (currentArg.equals("-classpath") //$NON-NLS-1$ || currentArg.equals("-cp")) { //$NON-NLS-1$ //$NON-NLS-2$ if (pathCount > 0) throw new InvalidInputException( Main.bind("configure.duplicateClasspath", currentArg)); //$NON-NLS-1$ classpaths = new String[DEFAULT_SIZE_CLASSPATH]; mode = InsideClasspath; continue; } if (currentArg.equals("-progress")) { //$NON-NLS-1$ mode = Default; showProgress = true; continue; } if (currentArg.equals("-proceedOnError")) { //$NON-NLS-1$ mode = Default; proceedOnError = true; continue; } if (currentArg.equals("-time")) { //$NON-NLS-1$ mode = Default; timer = true; continue; } if (currentArg.equals("-version") //$NON-NLS-1$ || currentArg.equals("-v")) { //$NON-NLS-1$ //$NON-NLS-2$ versionIDRequired = true; continue; } if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$ warnOptionInUse = true; if (noWarnOptionInUse) throw new InvalidInputException( Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); continue; } if (currentArg.equals("-help")) { //$NON-NLS-1$ printUsageRequired = true; continue; } if (currentArg.equals("-noImportError")) { //$NON-NLS-1$ mode = Default; options.put( CompilerOptions.OPTION_ReportInvalidImport, CompilerOptions.WARNING); continue; } if (currentArg.equals("-noExit")) { //$NON-NLS-1$ mode = Default; systemExitWhenFinished = false; continue; } if (currentArg.equals("-verbose")) { //$NON-NLS-1$ mode = Default; verbose = true; continue; } if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$ mode = Default; produceRefInfo = true; continue; } if (currentArg.startsWith("-g")) { //$NON-NLS-1$ mode = Default; String debugOption = currentArg; int length = currentArg.length(); if (length == 2) { options.put( CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); options.put( CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); options.put( CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); continue; } if (length > 3) { options.put( CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.DO_NOT_GENERATE); options.put( CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.DO_NOT_GENERATE); 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$ options.put( CompilerOptions.OPTION_LocalVariableAttribute, CompilerOptions.GENERATE); } else if (token.equals("lines")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_LineNumberAttribute, CompilerOptions.GENERATE); } else if (token.equals("source")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_SourceFileAttribute, CompilerOptions.GENERATE); } else { throw new InvalidInputException( Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ //$NON-NLS-1$ } } continue; } throw new InvalidInputException( Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$ } if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$ noWarnOptionInUse = true; noWarn = true; if (warnOptionInUse) throw new InvalidInputException( Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ mode = Default; continue; } if (currentArg.startsWith("-warn")) { //$NON-NLS-1$ warnOptionInUse = true; if (noWarnOptionInUse) throw new InvalidInputException( Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$ mode = Default; String warningOption = currentArg; int length = currentArg.length(); if (length == 10 && warningOption.equals("-warn:none")) { //$NON-NLS-1$ noWarn = true; continue; } if (length < 6) throw new InvalidInputException( Main.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$ StringTokenizer tokenizer = new StringTokenizer(warningOption.substring(6, warningOption.length()), ","); //$NON-NLS-1$ int tokenCounter = 0; options.put( CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportMethodWithConstructorName, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportHiddenCatchBlock, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportAssertIdentifier, CompilerOptions.IGNORE); options.put( CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.IGNORE); while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); tokenCounter++; if (token.equals("constructorName")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportMethodWithConstructorName, CompilerOptions.WARNING); } else if (token.equals("packageDefaultMethod")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod, CompilerOptions.WARNING); } else if (token.equals("maskedCatchBlocks")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportHiddenCatchBlock, CompilerOptions.WARNING); } else if (token.equals("deprecation")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING); } else if (token.equals("unusedLocals")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.WARNING); } else if (token.equals("unusedArguments")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportUnusedParameter, CompilerOptions.WARNING); } else if (token.equals("unusedImports")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportUnusedImport, CompilerOptions.WARNING); } else if (token.equals("syntheticAccess")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportSyntheticAccessEmulation, CompilerOptions.WARNING); } else if (token.equals("nls")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportNonExternalizedStringLiteral, CompilerOptions.WARNING); } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_ReportAssertIdentifier, CompilerOptions.WARNING); } else { throw new InvalidInputException(Main.bind("configure.invalidWarning", token)); //$NON-NLS-1$ } } if (tokenCounter == 0) throw new InvalidInputException( Main.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$ continue; } if (currentArg.equals("-target")) { //$NON-NLS-1$ didSpecifyTarget = true; mode = TargetSetting; continue; } if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$ options.put( CompilerOptions.OPTION_PreserveUnusedLocal, CompilerOptions.PRESERVE); continue; } if (mode == TargetSetting) { if (currentArg.equals("1.1")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); } else if (currentArg.equals("1.2")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2); } else if (currentArg.equals("1.3")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_3); } else if (currentArg.equals("1.4")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); } else { throw new InvalidInputException(Main.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$ } mode = Default; continue; } if (mode == InsideLog) { log = currentArg; mode = Default; continue; } if (mode == InsideRepetition) { try { repetitions = Integer.parseInt(currentArg); if (repetitions <= 0) { throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$ } } catch (NumberFormatException e) { throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$ } mode = Default; continue; } if (mode == InsideSource) { if (currentArg.equals("1.3")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); } else if (currentArg.equals("1.4")) { //$NON-NLS-1$ options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); } else { throw new InvalidInputException(Main.bind("configure.source", currentArg)); //$NON-NLS-1$ } mode = Default; continue; } if (mode == InsideDefaultEncoding) { if (didSpecifyDefaultEncoding) { throw new InvalidInputException( Main.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( Main.bind("configure.unsupportedEncoding", currentArg)); //$NON-NLS-1$ } options.put(CompilerOptions.OPTION_Encoding, currentArg); didSpecifyDefaultEncoding = true; mode = Default; continue; } if (mode == InsideDestinationPath) { destinationPath = currentArg; mode = Default; continue; } if (mode == InsideClasspath) { StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator); while (tokenizer.hasMoreTokens()) { int length; if ((length = classpaths.length) <= pathCount) { System.arraycopy( classpaths, 0, (classpaths = new String[length * 2]), 0, length); } classpaths[pathCount++] = tokenizer.nextToken(); } mode = Default; continue; } //default is input directory currentArg = currentArg.replace('/', File.separatorChar); if (currentArg.endsWith(File.separator)) currentArg = currentArg.substring(0, currentArg.length() - File.separator.length()); File dir = new File(currentArg); if (!dir.isDirectory()) throw new InvalidInputException( Main.bind("configure.directoryNotExist", currentArg)); //$NON-NLS-1$ FileFinder finder = new FileFinder(); try { finder.find(dir, ".JAVA", verbose); //$NON-NLS-1$ } catch (Exception e) { throw new InvalidInputException(Main.bind("configure.IOError", currentArg)); //$NON-NLS-1$ } if (filenames != null) { // some source files were specified explicitly String results[] = finder.resultFiles; int length = results.length; System.arraycopy( filenames, 0, (filenames = new String[length + filesCount]), 0, filesCount); System.arraycopy( encodings, 0, (encodings = new String[length + filesCount]), 0, filesCount); System.arraycopy(results, 0, filenames, filesCount, length); for (int i = 0; i < length; i++) { encodings[filesCount + i] = customEncoding; } filesCount += length; customEncoding = null; } else { filenames = finder.resultFiles; filesCount = filenames.length; encodings = new String[filesCount]; for (int i = 0; i < filesCount; i++) { encodings[i] = customEncoding; } customEncoding = null; } mode = Default; continue; } if (noWarn) { // filter options which are related to the assist component Object[] entries = 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)) { options.put((String) entry.getKey(), CompilerOptions.IGNORE); } } } /* * Standalone options */ if (versionIDRequired) { out.println(Main.bind("configure.version", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$ out.println(); proceed = false; return; } if (printUsageRequired) { printUsage(); proceed = false; return; } if (filesCount != 0) System.arraycopy( filenames, 0, (filenames = new String[filesCount]), 0, filesCount); if (pathCount == 0) { String classProp = System.getProperty("DEFAULT_CLASSPATH"); //$NON-NLS-1$ if ((classProp == null) || (classProp.length() == 0)) { out.println(Main.bind("configure.noClasspath")); //$NON-NLS-1$ classProp = "."; //$NON-NLS-1$ } StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator); classpaths = new String[tokenizer.countTokens()]; while (tokenizer.hasMoreTokens()) { classpaths[pathCount++] = tokenizer.nextToken(); } } if (classpaths == null) classpaths = new String[0]; System.arraycopy( classpaths, 0, (classpaths = new String[pathCount]), 0, pathCount); for (int i = 0, max = classpaths.length; i < max; i++) { File file = new File(classpaths[i]); if (!file.exists()) // signal missing classpath entry file out.println(Main.bind("configure.incorrectClasspath", classpaths[i])); //$NON-NLS-1$ } if (destinationPath == null) { generatePackagesStructure = false; } else if ("none".equals(destinationPath)) { //$NON-NLS-1$ destinationPath = null; } if (filenames == null) throw new InvalidInputException(Main.bind("configure.noSource")); //$NON-NLS-1$ // check and set compliance/source/target compatibilities if (!didSpecifyCompliance){ if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4)){ options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4); } else { options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3); } } String compliance = (String)options.get(CompilerOptions.OPTION_Compliance); if (CompilerOptions.VERSION_1_4.equals(compliance)){ // default 1.4 settings if (!didSpecifySourceLevel){ options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); } if (!didSpecifyTarget){ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4); } } else if (CompilerOptions.VERSION_1_3.equals(compliance)){ // default 1.4 settings if (!didSpecifySourceLevel){ options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3); } if (!didSpecifyTarget){ options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1); } } // compliance must be 1.4 if source is 1.4 if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4) && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){ throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForSource14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$ } // target must be 1.4 if source is 1.4 if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4) && !options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4)){ throw new InvalidInputException(Main.bind("configure.incompatibleTargetForSource14", (String)options.get(CompilerOptions.OPTION_TargetPlatform))); //$NON-NLS-1$ } // target cannot be 1.4 if compliance is 1.3 if (options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4) && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){ throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForTarget14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$ } if (log != null) { try { out = new PrintWriter(new FileOutputStream(log, false)); } catch (IOException e) { throw new InvalidInputException(Main.bind("configure.cannotOpenLog")); //$NON-NLS-1$ } } else { showProgress = false; } if (repetitions == 0) { repetitions = 1; } } public Map getOptions() { return this.options; } /* * 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; lineCount += unitLineCount; lineDelta += unitLineCount; if (showProgress && lineDelta > 2000) { // in -log mode, dump a dot every 2000 lines compiled System.out.print('.'); lineDelta = 0; } } if (compilationResult.hasProblems()) { IProblem[] problems = compilationResult.getProblems(); int count = problems.length; int localErrorCount = 0; for (int i = 0; i < count; i++) { if (problems[i] != null) { globalProblemsCount++; if (localErrorCount == 0) out.println("----------"); //$NON-NLS-1$ out.print( globalProblemsCount + ". " //$NON-NLS-1$ + (problems[i].isError() ? Main.bind("requestor.error") //$NON-NLS-1$ : Main.bind("requestor.warning"))); //$NON-NLS-1$ if (problems[i].isError()) { globalErrorsCount++; } else { globalWarningsCount++; } out.print(" "); //$NON-NLS-1$ out.print( Main.bind("requestor.in", new String(problems[i].getOriginatingFileName()))); //$NON-NLS-1$ try { out.println( ((DefaultProblem) problems[i]).errorReportSource( compilationResult.compilationUnit)); out.println(problems[i].getMessage()); } catch (Exception e) { out.println( Main.bind("requestor.notRetrieveErrorMessage", problems[i].toString())); //$NON-NLS-1$ } out.println("----------"); //$NON-NLS-1$ if (problems[i].isError()) localErrorCount++; } }; // exit? if (systemExitWhenFinished && !proceedOnError && (localErrorCount > 0)) { out.flush(); System.exit(-1); } } outputClassFiles(compilationResult); } }; } /* * Build the set of compilation source units */ public CompilationUnit[] getCompilationUnits() throws InvalidInputException { int fileCount = filenames.length; CompilationUnit[] units = new CompilationUnit[fileCount]; HashtableOfObject knownFileNames = new HashtableOfObject(fileCount); String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding); if ("".equals(defaultEncoding)) //$NON-NLS-1$ defaultEncoding = null; //$NON-NLS-1$ for (int i = 0; i < fileCount; i++) { char[] charName = filenames[i].toCharArray(); if (knownFileNames.get(charName) != null) { throw new InvalidInputException(Main.bind("unit.more", filenames[i])); //$NON-NLS-1$ } else { knownFileNames.put(charName, charName); } File file = new File(filenames[i]); if (!file.exists()) throw new InvalidInputException(Main.bind("unit.missing", filenames[i])); //$NON-NLS-1$ String encoding = encodings[i]; if (encoding == null) encoding = defaultEncoding; units[i] = new CompilationUnit(null, filenames[i], encoding); } 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 stopOnFirstError() { return false; } public boolean proceedOnErrors() { return proceedOnError; // stop if there are some errors } }; } /* * Low-level API performing the actual compilation */ public FileSystem getLibraryAccess() { String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding); if ("".equals(defaultEncoding)) //$NON-NLS-1$ defaultEncoding = null; //$NON-NLS-1$ return new FileSystem(classpaths, filenames, defaultEncoding); } /* * Low-level API performing the actual compilation */ public IProblemFactory getProblemFactory() { return new DefaultProblemFactory(Locale.getDefault()); } /* * External API */ public static void main(String[] argv) { new Main(new PrintWriter(System.out), true).compile(argv); } // Dump classfiles onto disk for all compilation units that where successfull. public void outputClassFiles(CompilationResult unitResult) { if (!((unitResult == null) || (unitResult.hasErrors() && !proceedOnError))) { Enumeration classFiles = unitResult.compiledTypes.elements(); if (!this.generatePackagesStructure) { while (classFiles.hasMoreElements()) { this.destinationPath = extractDestinationPathFromSourceFile(unitResult); // retrieve the key and the corresponding classfile ClassFile classFile = (ClassFile) classFiles.nextElement(); char[] filename = classFile.fileName(); int length = filename.length; char[] relativeName = new char[length + 6]; System.arraycopy(filename, 0, relativeName, 0, length); System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6); CharOperation.replace(relativeName, '/', File.separatorChar); try { ClassFile.writeToDisk( generatePackagesStructure, destinationPath, new String(relativeName), classFile.getBytes()); } catch (IOException e) { String fileName = destinationPath + new String(relativeName); e.printStackTrace(); System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$ } exportedClassFilesCounter++; } } else if (destinationPath != null) { while (classFiles.hasMoreElements()) { // retrieve the key and the corresponding classfile ClassFile classFile = (ClassFile) classFiles.nextElement(); char[] filename = classFile.fileName(); int length = filename.length; char[] relativeName = new char[length + 6]; System.arraycopy(filename, 0, relativeName, 0, length); System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6); CharOperation.replace(relativeName, '/', File.separatorChar); try { ClassFile.writeToDisk( generatePackagesStructure, destinationPath, new String(relativeName), classFile.getBytes()); } catch (IOException e) { String fileName = destinationPath + new String(relativeName); e.printStackTrace(); System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$ } exportedClassFilesCounter++; } } } } /* * Low-level API performing the actual compilation */ public void performCompilation() throws InvalidInputException { INameEnvironment environment = getLibraryAccess(); Compiler batchCompiler = new Compiler( environment, getHandlingPolicy(), getOptions(), getBatchRequestor(), getProblemFactory()); CompilerOptions options = batchCompiler.options; // set the non-externally configurable options. options.setVerboseMode(verbose); options.produceReferenceInfo(produceRefInfo); batchCompiler.compile(getCompilationUnits()); // cleanup environment.cleanup(); } public void printUsage() { out.println(Main.bind("misc.usage", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$ out.flush(); } /** * Creates a NLS catalog for the given locale. */ public static void relocalize() { bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); } /** * Lookup the message with the given ID in this catalog */ public static 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 values. */ public static String bind(String id, String[] bindings) { if (id == null) return "No message available"; //$NON-NLS-1$ String message = null; try { message = 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: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$ } // for compatibility with MessageFormat which eliminates double quotes in original message char[] messageWithNoDoubleQuotes = CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE); message = new String(messageWithNoDoubleQuotes); if (bindings == null) return message; int length = message.length(); int start = -1; int end = length; StringBuffer output = new StringBuffer(80); while (true) { if ((end = message.indexOf('{', start)) > -1) { output.append(message.substring(start + 1, end)); if ((start = message.indexOf('}', end)) > -1) { int index = -1; try { index = Integer.parseInt(message.substring(end + 1, start)); output.append(bindings[index]); } catch (NumberFormatException nfe) { output.append(message.substring(end + 1, start + 1)); } catch (ArrayIndexOutOfBoundsException e) { output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$ } } else { output.append(message.substring(end, length)); break; } } else { output.append(message.substring(start + 1, length)); break; } } return output.toString(); } /** * Lookup the message with the given ID in this catalog and bind its * substitution locations with the given string. */ public static 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 static String bind(String id, String binding1, String binding2) { return bind(id, new String[] { binding1, binding2 }); } 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) { return System.getProperty("user.dir"); //$NON-NLS-1$ } return new String(CharOperation.subarray(fileName, 0, lastIndex)); } return System.getProperty("user.dir"); //$NON-NLS-1$ } }