1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.batch;
13 import java.io.ByteArrayInputStream;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.io.InputStreamReader;
18 import java.io.PrintWriter;
19 import java.io.UnsupportedEncodingException;
20 import java.util.Enumeration;
21 import java.util.Hashtable;
22 import java.util.Locale;
24 import java.util.MissingResourceException;
25 import java.util.ResourceBundle;
26 import java.util.StringTokenizer;
28 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
29 import net.sourceforge.phpdt.core.compiler.IProblem;
30 import net.sourceforge.phpdt.internal.compiler.ClassFile;
31 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
32 import net.sourceforge.phpdt.internal.compiler.Compiler;
33 import net.sourceforge.phpdt.internal.compiler.ICompilerRequestor;
34 import net.sourceforge.phpdt.internal.compiler.IErrorHandlingPolicy;
35 import net.sourceforge.phpdt.internal.compiler.IProblemFactory;
36 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
37 import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment;
38 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
39 import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblem;
40 import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory;
41 import net.sourceforge.phpdt.internal.compiler.problem.ProblemSeverities;
42 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
43 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
45 public class Main implements ProblemSeverities {
47 public boolean noWarn = false;
49 public PrintWriter out;
50 public boolean systemExitWhenFinished = true;
51 public boolean proceedOnError = false;
53 public boolean verbose = false;
54 public boolean produceRefInfo = false;
55 public boolean timer = false;
56 public boolean showProgress = false;
58 public long lineCount;
59 public boolean generatePackagesStructure;
61 public Hashtable options;
62 public String[] filenames;
63 public String[] encodings;
64 public String[] classpaths;
65 public String destinationPath;
67 public int repetitions;
68 public int globalProblemsCount;
69 public int globalErrorsCount;
70 public int globalWarningsCount;
71 public int exportedClassFilesCounter;
73 public static final char[] CLASS_FILE_EXTENSION = ".class".toCharArray(); //$NON-NLS-1$
74 public final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
75 public final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
77 /* Bundle containing messages */
78 public static ResourceBundle bundle;
79 public final static String bundleName =
80 "org.eclipse.jdt.internal.compiler.batch.messages"; //$NON-NLS-1$
86 public boolean proceed = true;
88 public Main(PrintWriter writer, boolean systemExitWhenFinished) {
91 this.systemExitWhenFinished = systemExitWhenFinished;
92 exportedClassFilesCounter = 0;
93 options = new Hashtable();
95 CompilerOptions.OPTION_LocalVariableAttribute,
96 CompilerOptions.DO_NOT_GENERATE);
98 CompilerOptions.OPTION_LineNumberAttribute,
99 CompilerOptions.DO_NOT_GENERATE);
101 CompilerOptions.OPTION_SourceFileAttribute,
102 CompilerOptions.DO_NOT_GENERATE);
104 CompilerOptions.OPTION_PreserveUnusedLocal,
105 CompilerOptions.OPTIMIZE_OUT);
107 CompilerOptions.OPTION_ReportUnreachableCode,
108 CompilerOptions.ERROR);
109 options.put(CompilerOptions.OPTION_ReportInvalidImport, CompilerOptions.ERROR);
111 CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
112 CompilerOptions.WARNING);
114 CompilerOptions.OPTION_ReportMethodWithConstructorName,
115 CompilerOptions.WARNING);
116 options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
118 CompilerOptions.OPTION_ReportHiddenCatchBlock,
119 CompilerOptions.WARNING);
120 options.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
122 CompilerOptions.OPTION_ReportUnusedParameter,
123 CompilerOptions.IGNORE);
125 CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
126 CompilerOptions.IGNORE);
128 CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
129 CompilerOptions.IGNORE);
131 CompilerOptions.OPTION_ReportAssertIdentifier,
132 CompilerOptions.IGNORE);
134 CompilerOptions.OPTION_Compliance,
135 CompilerOptions.VERSION_1_3);
137 CompilerOptions.OPTION_Source,
138 CompilerOptions.VERSION_1_3);
140 CompilerOptions.OPTION_TargetPlatform,
141 CompilerOptions.VERSION_1_1);
145 * Low-level API performing the actual compilation
147 public boolean compile(String[] argv) {
149 // decode command line arguments
154 out.print(Main.bind("progress.compiling")); //$NON-NLS-1$
155 for (int i = 0; i < repetitions; i++) {
156 globalProblemsCount = 0;
157 globalErrorsCount = 0;
158 globalWarningsCount = 0;
161 if (repetitions > 1) {
165 "compile.repetition", //$NON-NLS-1$
166 String.valueOf(i + 1),
167 String.valueOf(repetitions)));
169 long startTime = System.currentTimeMillis();
170 // request compilation
171 performCompilation();
174 time = System.currentTimeMillis() - startTime;
175 if (lineCount != 0) {
178 "compile.instantTime", //$NON-NLS-1$
180 String.valueOf(lineCount),
181 String.valueOf(time),
182 String.valueOf((((int) ((lineCount * 10000.0) / time)) / 10.0))}));
184 out.println(Main.bind("compile.totalTime", String.valueOf(time))); //$NON-NLS-1$
187 if (globalProblemsCount > 0) {
188 if (globalProblemsCount == 1) {
189 out.print(Main.bind("compile.oneProblem")); //$NON-NLS-1$
192 Main.bind("compile.severalProblems", String.valueOf(globalProblemsCount))); //$NON-NLS-1$
194 out.print(" ("); //$NON-NLS-1$
195 if (globalErrorsCount > 0) {
196 if (globalErrorsCount == 1) {
197 out.print(Main.bind("compile.oneError")); //$NON-NLS-1$
200 Main.bind("compile.severalErrors", String.valueOf(globalErrorsCount))); //$NON-NLS-1$
203 if (globalWarningsCount > 0) {
204 if (globalErrorsCount > 0) {
205 out.print(", "); //$NON-NLS-1$
207 if (globalWarningsCount == 1) {
208 out.print(Main.bind("compile.oneWarning")); //$NON-NLS-1$
211 Main.bind("compile.severalWarnings", String.valueOf(globalWarningsCount))); //$NON-NLS-1$
214 out.println(")"); //$NON-NLS-1$
216 if (exportedClassFilesCounter != 0
217 && (this.showProgress || this.timer || this.verbose)) {
218 if (exportedClassFilesCounter == 1) {
219 out.print(Main.bind("compile.oneClassFileGenerated")); //$NON-NLS-1$
223 "compile.severalClassFilesGenerated", //$NON-NLS-1$
224 String.valueOf(exportedClassFilesCounter)));
229 System.out.println();
231 if (systemExitWhenFinished) {
233 System.exit(globalErrorsCount > 0 ? -1 : 0);
235 } catch (InvalidInputException e) {
236 out.println(e.getMessage());
237 out.println("------------------------"); //$NON-NLS-1$
239 if (systemExitWhenFinished) {
242 } catch (ThreadDeath e) { // do not stop this one
244 } catch (Throwable e) { // internal compiler error
245 if (systemExitWhenFinished) {
247 if (this.log != null) {
252 //e.printStackTrace();
255 if (this.log != null) {
259 if (globalErrorsCount == 0){
269 public static boolean compile(String commandLine) {
271 return compile(commandLine, new PrintWriter(System.out));
275 * Internal IDE API for test harness purpose
277 public static boolean compile(String commandLine, PrintWriter writer) {
279 return new Main(writer, false).compile(tokenize(commandLine));
282 public static String[] tokenize(String commandLine) {
285 String[] arguments = new String[10];
286 StringTokenizer tokenizer = new StringTokenizer(commandLine, " \"", true); //$NON-NLS-1$
287 String token = "", lastToken; //$NON-NLS-1$
288 boolean insideQuotes = false;
289 boolean startNewToken = true;
291 // take care to quotes on the command line
292 // 'xxx "aaa bbb";ccc yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" }
293 // 'xxx "aaa bbb;ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" }
294 // 'xxx "aaa bbb";"ccc" yyy' ---> {"xxx", "aaa bbb;ccc", "yyy" }
295 // 'xxx/"aaa bbb";"ccc" yyy' ---> {"xxx/aaa bbb;ccc", "yyy" }
296 while (tokenizer.hasMoreTokens()) {
298 token = tokenizer.nextToken();
300 if (token.equals(" ")) { //$NON-NLS-1$
302 arguments[count - 1] += token;
303 startNewToken = false;
305 startNewToken = true;
307 } else if (token.equals("\"")) { //$NON-NLS-1$
308 if (!insideQuotes && startNewToken) { //$NON-NLS-1$
309 if (count == arguments.length)
310 System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
311 arguments[count++] = ""; //$NON-NLS-1$
313 insideQuotes = !insideQuotes;
314 startNewToken = false;
317 arguments[count - 1] += token;
319 if (token.length() > 0 && !startNewToken) {
320 arguments[count - 1] += token;
322 if (count == arguments.length)
323 System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
324 arguments[count++] = token;
327 startNewToken = false;
330 System.arraycopy(arguments, 0, arguments = new String[count], 0, count);
335 Decode the command line arguments
337 public void configure(String[] argv) throws InvalidInputException {
339 if ((argv == null) || (argv.length == 0))
340 throw new InvalidInputException(Main.bind("configure.noSourceFile")); //$NON-NLS-1$
341 final int InsideClasspath = 1;
342 final int InsideDestinationPath = 2;
343 final int TargetSetting = 4;
344 final int InsideLog = 8;
345 final int InsideRepetition = 16;
346 final int InsideSource = 32;
347 final int InsideDefaultEncoding = 64;
348 final int Default = 0;
349 int DEFAULT_SIZE_CLASSPATH = 4;
350 boolean warnOptionInUse = false;
351 boolean noWarnOptionInUse = false;
353 int index = -1, filesCount = 0, argCount = argv.length;
356 boolean versionIDRequired = false;
357 boolean printUsageRequired = false;
359 boolean didSpecifyCompliance = false;
360 boolean didSpecifySourceLevel = false;
361 boolean didSpecifyDefaultEncoding = false;
362 boolean didSpecifyTarget = false;
364 String customEncoding = null;
365 String currentArg = ""; //$NON-NLS-1$
367 while (++index < argCount) {
369 if (customEncoding != null) {
370 throw new InvalidInputException(
371 Main.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$
374 currentArg = argv[index].trim();
376 customEncoding = null;
377 if (currentArg.endsWith("]")) { //$NON-NLS-1$
378 // look for encoding specification
379 int encodingStart = currentArg.indexOf('[') + 1;
380 int encodingEnd = currentArg.length() - 1;
381 if (encodingStart >= 1) {
382 if (encodingStart < encodingEnd) {
383 customEncoding = currentArg.substring(encodingStart, encodingEnd);
384 try { // ensure encoding is supported
385 new InputStreamReader(new ByteArrayInputStream(new byte[0]), customEncoding);
386 } catch (UnsupportedEncodingException e) {
387 throw new InvalidInputException(
388 Main.bind("configure.unsupportedEncoding", customEncoding)); //$NON-NLS-1$
391 currentArg = currentArg.substring(0, encodingStart - 1);
395 if (currentArg.endsWith(".java")) { //$NON-NLS-1$
396 if (filenames == null) {
397 filenames = new String[argCount - index];
398 encodings = new String[argCount - index];
399 } else if (filesCount == filenames.length) {
400 int length = filenames.length;
404 (filenames = new String[length + argCount - index]),
410 (encodings = new String[length + argCount - index]),
414 filenames[filesCount] = currentArg;
415 encodings[filesCount++] = customEncoding;
416 customEncoding = null;
420 if (currentArg.equals("-log")) { //$NON-NLS-1$
422 throw new InvalidInputException(
423 Main.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$
427 if (currentArg.equals("-repeat")) { //$NON-NLS-1$
429 throw new InvalidInputException(
430 Main.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$
431 mode = InsideRepetition;
434 if (currentArg.equals("-source")) { //$NON-NLS-1$
436 didSpecifySourceLevel = true;
439 if (currentArg.equals("-encoding")) { //$NON-NLS-1$
440 mode = InsideDefaultEncoding;
443 if (currentArg.equals("-1.3")) { //$NON-NLS-1$
444 if (didSpecifyCompliance) {
445 throw new InvalidInputException(
446 Main.bind("configure.duplicateCompliance", currentArg));//$NON-NLS-1$
448 didSpecifyCompliance = true;
449 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3);
453 if (currentArg.equals("-1.4")) { //$NON-NLS-1$
454 if (didSpecifyCompliance) {
455 throw new InvalidInputException(
456 Main.bind("configure.duplicateCompliance", currentArg)); //$NON-NLS-1$
458 didSpecifyCompliance = true;
459 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
463 if (currentArg.equals("-d")) { //$NON-NLS-1$
464 if (destinationPath != null)
465 throw new InvalidInputException(
466 Main.bind("configure.duplicateOutputPath", currentArg)); //$NON-NLS-1$
467 mode = InsideDestinationPath;
468 generatePackagesStructure = true;
471 if (currentArg.equals("-classpath") //$NON-NLS-1$
472 || currentArg.equals("-cp")) { //$NON-NLS-1$ //$NON-NLS-2$
474 throw new InvalidInputException(
475 Main.bind("configure.duplicateClasspath", currentArg)); //$NON-NLS-1$
476 classpaths = new String[DEFAULT_SIZE_CLASSPATH];
477 mode = InsideClasspath;
480 if (currentArg.equals("-progress")) { //$NON-NLS-1$
485 if (currentArg.equals("-proceedOnError")) { //$NON-NLS-1$
487 proceedOnError = true;
490 if (currentArg.equals("-time")) { //$NON-NLS-1$
495 if (currentArg.equals("-version") //$NON-NLS-1$
496 || currentArg.equals("-v")) { //$NON-NLS-1$ //$NON-NLS-2$
497 versionIDRequired = true;
500 if ("-deprecation".equals(currentArg)) { //$NON-NLS-1$
501 warnOptionInUse = true;
502 if (noWarnOptionInUse)
503 throw new InvalidInputException(
504 Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$
505 options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
508 if (currentArg.equals("-help")) { //$NON-NLS-1$
509 printUsageRequired = true;
512 if (currentArg.equals("-noImportError")) { //$NON-NLS-1$
515 CompilerOptions.OPTION_ReportInvalidImport,
516 CompilerOptions.WARNING);
519 if (currentArg.equals("-noExit")) { //$NON-NLS-1$
521 systemExitWhenFinished = false;
524 if (currentArg.equals("-verbose")) { //$NON-NLS-1$
529 if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$
531 produceRefInfo = true;
534 if (currentArg.startsWith("-g")) { //$NON-NLS-1$
536 String debugOption = currentArg;
537 int length = currentArg.length();
540 CompilerOptions.OPTION_LocalVariableAttribute,
541 CompilerOptions.GENERATE);
543 CompilerOptions.OPTION_LineNumberAttribute,
544 CompilerOptions.GENERATE);
546 CompilerOptions.OPTION_SourceFileAttribute,
547 CompilerOptions.GENERATE);
552 CompilerOptions.OPTION_LocalVariableAttribute,
553 CompilerOptions.DO_NOT_GENERATE);
555 CompilerOptions.OPTION_LineNumberAttribute,
556 CompilerOptions.DO_NOT_GENERATE);
558 CompilerOptions.OPTION_SourceFileAttribute,
559 CompilerOptions.DO_NOT_GENERATE);
560 if (length == 7 && debugOption.equals("-g:none")) //$NON-NLS-1$
562 StringTokenizer tokenizer =
563 new StringTokenizer(debugOption.substring(3, debugOption.length()), ","); //$NON-NLS-1$
564 while (tokenizer.hasMoreTokens()) {
565 String token = tokenizer.nextToken();
566 if (token.equals("vars")) { //$NON-NLS-1$
568 CompilerOptions.OPTION_LocalVariableAttribute,
569 CompilerOptions.GENERATE);
570 } else if (token.equals("lines")) { //$NON-NLS-1$
572 CompilerOptions.OPTION_LineNumberAttribute,
573 CompilerOptions.GENERATE);
574 } else if (token.equals("source")) { //$NON-NLS-1$
576 CompilerOptions.OPTION_SourceFileAttribute,
577 CompilerOptions.GENERATE);
579 throw new InvalidInputException(
580 Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
586 throw new InvalidInputException(
587 Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
589 if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$
590 noWarnOptionInUse = true;
593 throw new InvalidInputException(
594 Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$
598 if (currentArg.startsWith("-warn")) { //$NON-NLS-1$
599 warnOptionInUse = true;
600 if (noWarnOptionInUse)
601 throw new InvalidInputException(
602 Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$
604 String warningOption = currentArg;
605 int length = currentArg.length();
606 if (length == 10 && warningOption.equals("-warn:none")) { //$NON-NLS-1$
611 throw new InvalidInputException(
612 Main.bind("configure.invalidWarningConfiguration", warningOption)); //$NON-NLS-1$
613 StringTokenizer tokenizer =
614 new StringTokenizer(warningOption.substring(6, warningOption.length()), ","); //$NON-NLS-1$
615 int tokenCounter = 0;
618 CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
619 CompilerOptions.IGNORE);
621 CompilerOptions.OPTION_ReportMethodWithConstructorName,
622 CompilerOptions.IGNORE);
624 CompilerOptions.OPTION_ReportDeprecation,
625 CompilerOptions.IGNORE);
627 CompilerOptions.OPTION_ReportHiddenCatchBlock,
628 CompilerOptions.IGNORE);
630 CompilerOptions.OPTION_ReportUnusedLocal,
631 CompilerOptions.IGNORE);
633 CompilerOptions.OPTION_ReportUnusedParameter,
634 CompilerOptions.IGNORE);
636 CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
637 CompilerOptions.IGNORE);
639 CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
640 CompilerOptions.IGNORE);
642 CompilerOptions.OPTION_ReportAssertIdentifier,
643 CompilerOptions.IGNORE);
645 CompilerOptions.OPTION_ReportUnusedImport,
646 CompilerOptions.IGNORE);
648 while (tokenizer.hasMoreTokens()) {
649 String token = tokenizer.nextToken();
651 if (token.equals("constructorName")) { //$NON-NLS-1$
653 CompilerOptions.OPTION_ReportMethodWithConstructorName,
654 CompilerOptions.WARNING);
655 } else if (token.equals("packageDefaultMethod")) { //$NON-NLS-1$
657 CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
658 CompilerOptions.WARNING);
659 } else if (token.equals("maskedCatchBlocks")) { //$NON-NLS-1$
661 CompilerOptions.OPTION_ReportHiddenCatchBlock,
662 CompilerOptions.WARNING);
663 } else if (token.equals("deprecation")) { //$NON-NLS-1$
665 CompilerOptions.OPTION_ReportDeprecation,
666 CompilerOptions.WARNING);
667 } else if (token.equals("unusedLocals")) { //$NON-NLS-1$
669 CompilerOptions.OPTION_ReportUnusedLocal,
670 CompilerOptions.WARNING);
671 } else if (token.equals("unusedArguments")) { //$NON-NLS-1$
673 CompilerOptions.OPTION_ReportUnusedParameter,
674 CompilerOptions.WARNING);
675 } else if (token.equals("unusedImports")) { //$NON-NLS-1$
677 CompilerOptions.OPTION_ReportUnusedImport,
678 CompilerOptions.WARNING);
679 } else if (token.equals("syntheticAccess")) { //$NON-NLS-1$
681 CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
682 CompilerOptions.WARNING);
683 } else if (token.equals("nls")) { //$NON-NLS-1$
685 CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
686 CompilerOptions.WARNING);
687 } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$
689 CompilerOptions.OPTION_ReportAssertIdentifier,
690 CompilerOptions.WARNING);
692 throw new InvalidInputException(Main.bind("configure.invalidWarning", token)); //$NON-NLS-1$
695 if (tokenCounter == 0)
696 throw new InvalidInputException(
697 Main.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$
700 if (currentArg.equals("-target")) { //$NON-NLS-1$
701 didSpecifyTarget = true;
702 mode = TargetSetting;
705 if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$
707 CompilerOptions.OPTION_PreserveUnusedLocal,
708 CompilerOptions.PRESERVE);
711 if (mode == TargetSetting) {
712 if (currentArg.equals("1.1")) { //$NON-NLS-1$
713 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
714 } else if (currentArg.equals("1.2")) { //$NON-NLS-1$
715 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_2);
716 } else if (currentArg.equals("1.3")) { //$NON-NLS-1$
717 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_3);
718 } else if (currentArg.equals("1.4")) { //$NON-NLS-1$
719 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
721 throw new InvalidInputException(Main.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$
726 if (mode == InsideLog) {
731 if (mode == InsideRepetition) {
733 repetitions = Integer.parseInt(currentArg);
734 if (repetitions <= 0) {
735 throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$
737 } catch (NumberFormatException e) {
738 throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$
743 if (mode == InsideSource) {
744 if (currentArg.equals("1.3")) { //$NON-NLS-1$
745 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
746 } else if (currentArg.equals("1.4")) { //$NON-NLS-1$
747 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4);
749 throw new InvalidInputException(Main.bind("configure.source", currentArg)); //$NON-NLS-1$
754 if (mode == InsideDefaultEncoding) {
755 if (didSpecifyDefaultEncoding) {
756 throw new InvalidInputException(
757 Main.bind("configure.duplicateDefaultEncoding", currentArg)); //$NON-NLS-1$
759 try { // ensure encoding is supported
760 new InputStreamReader(new ByteArrayInputStream(new byte[0]), currentArg);
761 } catch (UnsupportedEncodingException e) {
762 throw new InvalidInputException(
763 Main.bind("configure.unsupportedEncoding", currentArg)); //$NON-NLS-1$
765 options.put(CompilerOptions.OPTION_Encoding, currentArg);
766 didSpecifyDefaultEncoding = true;
770 if (mode == InsideDestinationPath) {
771 destinationPath = currentArg;
775 if (mode == InsideClasspath) {
776 StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator);
777 while (tokenizer.hasMoreTokens()) {
779 if ((length = classpaths.length) <= pathCount) {
783 (classpaths = new String[length * 2]),
787 classpaths[pathCount++] = tokenizer.nextToken();
792 //default is input directory
793 currentArg = currentArg.replace('/', File.separatorChar);
794 if (currentArg.endsWith(File.separator))
796 currentArg.substring(0, currentArg.length() - File.separator.length());
797 File dir = new File(currentArg);
798 if (!dir.isDirectory())
799 throw new InvalidInputException(
800 Main.bind("configure.directoryNotExist", currentArg)); //$NON-NLS-1$
801 FileFinder finder = new FileFinder();
803 finder.find(dir, ".JAVA", verbose); //$NON-NLS-1$
804 } catch (Exception e) {
805 throw new InvalidInputException(Main.bind("configure.IOError", currentArg)); //$NON-NLS-1$
807 if (filenames != null) {
808 // some source files were specified explicitly
809 String results[] = finder.resultFiles;
810 int length = results.length;
814 (filenames = new String[length + filesCount]),
820 (encodings = new String[length + filesCount]),
823 System.arraycopy(results, 0, filenames, filesCount, length);
824 for (int i = 0; i < length; i++) {
825 encodings[filesCount + i] = customEncoding;
827 filesCount += length;
828 customEncoding = null;
830 filenames = finder.resultFiles;
831 filesCount = filenames.length;
832 encodings = new String[filesCount];
833 for (int i = 0; i < filesCount; i++) {
834 encodings[i] = customEncoding;
836 customEncoding = null;
843 // filter options which are related to the assist component
844 Object[] entries = options.entrySet().toArray();
845 for (int i = 0, max = entries.length; i < max; i++) {
846 Map.Entry entry = (Map.Entry) entries[i];
847 if (!(entry.getKey() instanceof String))
849 if (!(entry.getValue() instanceof String))
851 if (((String) entry.getValue()).equals(CompilerOptions.WARNING)) {
852 options.put((String) entry.getKey(), CompilerOptions.IGNORE);
859 if (versionIDRequired) {
860 out.println(Main.bind("configure.version", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$
866 if (printUsageRequired) {
876 (filenames = new String[filesCount]),
879 if (pathCount == 0) {
880 String classProp = System.getProperty("DEFAULT_CLASSPATH"); //$NON-NLS-1$
881 if ((classProp == null) || (classProp.length() == 0)) {
882 out.println(Main.bind("configure.noClasspath")); //$NON-NLS-1$
883 classProp = "."; //$NON-NLS-1$
885 StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
886 classpaths = new String[tokenizer.countTokens()];
887 while (tokenizer.hasMoreTokens()) {
888 classpaths[pathCount++] = tokenizer.nextToken();
892 if (classpaths == null)
893 classpaths = new String[0];
897 (classpaths = new String[pathCount]),
900 for (int i = 0, max = classpaths.length; i < max; i++) {
901 File file = new File(classpaths[i]);
902 if (!file.exists()) // signal missing classpath entry file
903 out.println(Main.bind("configure.incorrectClasspath", classpaths[i])); //$NON-NLS-1$
905 if (destinationPath == null) {
906 generatePackagesStructure = false;
907 } else if ("none".equals(destinationPath)) { //$NON-NLS-1$
908 destinationPath = null;
911 if (filenames == null)
912 throw new InvalidInputException(Main.bind("configure.noSource")); //$NON-NLS-1$
914 // check and set compliance/source/target compatibilities
915 if (!didSpecifyCompliance){
916 if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4)){
917 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
919 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3);
922 String compliance = (String)options.get(CompilerOptions.OPTION_Compliance);
923 if (CompilerOptions.VERSION_1_4.equals(compliance)){
925 // default 1.4 settings
926 if (!didSpecifySourceLevel){
927 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4);
929 if (!didSpecifyTarget){
930 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
932 } else if (CompilerOptions.VERSION_1_3.equals(compliance)){
934 // default 1.4 settings
935 if (!didSpecifySourceLevel){
936 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
938 if (!didSpecifyTarget){
939 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
942 // compliance must be 1.4 if source is 1.4
943 if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4)
944 && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){
945 throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForSource14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$
948 // target must be 1.4 if source is 1.4
949 if (options.get(CompilerOptions.OPTION_Source).equals(CompilerOptions.VERSION_1_4)
950 && !options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4)){
951 throw new InvalidInputException(Main.bind("configure.incompatibleTargetForSource14", (String)options.get(CompilerOptions.OPTION_TargetPlatform))); //$NON-NLS-1$
954 // target cannot be 1.4 if compliance is 1.3
955 if (options.get(CompilerOptions.OPTION_TargetPlatform).equals(CompilerOptions.VERSION_1_4)
956 && !options.get(CompilerOptions.OPTION_Compliance).equals(CompilerOptions.VERSION_1_4)){
957 throw new InvalidInputException(Main.bind("configure.incompatibleComplianceForTarget14", (String)options.get(CompilerOptions.OPTION_Compliance))); //$NON-NLS-1$
962 out = new PrintWriter(new FileOutputStream(log, false));
963 } catch (IOException e) {
964 throw new InvalidInputException(Main.bind("configure.cannotOpenLog")); //$NON-NLS-1$
967 showProgress = false;
970 if (repetitions == 0) {
974 public Map getOptions() {
978 * Answer the component to which will be handed back compilation results from the compiler
980 public ICompilerRequestor getBatchRequestor() {
981 return new ICompilerRequestor() {
983 public void acceptResult(CompilationResult compilationResult) {
984 if (compilationResult.lineSeparatorPositions != null) {
985 int unitLineCount = compilationResult.lineSeparatorPositions.length;
986 lineCount += unitLineCount;
987 lineDelta += unitLineCount;
989 && lineDelta > 2000) { // in -log mode, dump a dot every 2000 lines compiled
990 System.out.print('.');
994 if (compilationResult.hasProblems()) {
995 IProblem[] problems = compilationResult.getProblems();
996 int count = problems.length;
997 int localErrorCount = 0;
998 for (int i = 0; i < count; i++) {
999 if (problems[i] != null) {
1000 globalProblemsCount++;
1001 if (localErrorCount == 0)
1002 out.println("----------"); //$NON-NLS-1$
1005 + ". " //$NON-NLS-1$
1006 + (problems[i].isError()
1007 ? Main.bind("requestor.error") //$NON-NLS-1$
1008 : Main.bind("requestor.warning"))); //$NON-NLS-1$
1009 if (problems[i].isError()) {
1010 globalErrorsCount++;
1012 globalWarningsCount++;
1014 out.print(" "); //$NON-NLS-1$
1016 Main.bind("requestor.in", new String(problems[i].getOriginatingFileName()))); //$NON-NLS-1$
1019 ((DefaultProblem) problems[i]).errorReportSource(
1020 compilationResult.compilationUnit));
1021 out.println(problems[i].getMessage());
1022 } catch (Exception e) {
1024 Main.bind("requestor.notRetrieveErrorMessage", problems[i].toString())); //$NON-NLS-1$
1026 out.println("----------"); //$NON-NLS-1$
1027 if (problems[i].isError())
1032 if (systemExitWhenFinished && !proceedOnError && (localErrorCount > 0)) {
1037 outputClassFiles(compilationResult);
1042 * Build the set of compilation source units
1044 public CompilationUnit[] getCompilationUnits()
1045 throws InvalidInputException {
1046 int fileCount = filenames.length;
1047 CompilationUnit[] units = new CompilationUnit[fileCount];
1048 HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
1050 String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding);
1051 if ("".equals(defaultEncoding)) //$NON-NLS-1$
1052 defaultEncoding = null; //$NON-NLS-1$
1054 for (int i = 0; i < fileCount; i++) {
1055 char[] charName = filenames[i].toCharArray();
1056 if (knownFileNames.get(charName) != null) {
1057 throw new InvalidInputException(Main.bind("unit.more", filenames[i])); //$NON-NLS-1$
1059 knownFileNames.put(charName, charName);
1061 File file = new File(filenames[i]);
1063 throw new InvalidInputException(Main.bind("unit.missing", filenames[i])); //$NON-NLS-1$
1064 String encoding = encodings[i];
1065 if (encoding == null)
1066 encoding = defaultEncoding;
1067 units[i] = new CompilationUnit(null, filenames[i], encoding);
1072 * Low-level API performing the actual compilation
1074 public IErrorHandlingPolicy getHandlingPolicy() {
1076 // passes the initial set of files to the batch oracle (to avoid finding more than once the same units when case insensitive match)
1077 return new IErrorHandlingPolicy() {
1078 public boolean stopOnFirstError() {
1081 public boolean proceedOnErrors() {
1082 return proceedOnError; // stop if there are some errors
1087 * Low-level API performing the actual compilation
1089 public FileSystem getLibraryAccess() {
1091 String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding);
1092 if ("".equals(defaultEncoding)) //$NON-NLS-1$
1093 defaultEncoding = null; //$NON-NLS-1$
1094 return new FileSystem(classpaths, filenames, defaultEncoding);
1097 * Low-level API performing the actual compilation
1099 public IProblemFactory getProblemFactory() {
1100 return new DefaultProblemFactory(Locale.getDefault());
1106 public static void main(String[] argv) {
1107 new Main(new PrintWriter(System.out), true).compile(argv);
1109 // Dump classfiles onto disk for all compilation units that where successfull.
1111 public void outputClassFiles(CompilationResult unitResult) {
1113 if (!((unitResult == null) || (unitResult.hasErrors() && !proceedOnError))) {
1114 Enumeration classFiles = unitResult.compiledTypes.elements();
1115 if (!this.generatePackagesStructure) {
1116 while (classFiles.hasMoreElements()) {
1117 this.destinationPath = extractDestinationPathFromSourceFile(unitResult);
1118 // retrieve the key and the corresponding classfile
1119 ClassFile classFile = (ClassFile) classFiles.nextElement();
1120 char[] filename = classFile.fileName();
1121 int length = filename.length;
1122 char[] relativeName = new char[length + 6];
1123 System.arraycopy(filename, 0, relativeName, 0, length);
1124 System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6);
1125 CharOperation.replace(relativeName, '/', File.separatorChar);
1127 ClassFile.writeToDisk(
1128 generatePackagesStructure,
1130 new String(relativeName),
1131 classFile.getBytes());
1132 } catch (IOException e) {
1133 String fileName = destinationPath + new String(relativeName);
1134 e.printStackTrace();
1135 System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$
1137 exportedClassFilesCounter++;
1139 } else if (destinationPath != null) {
1140 while (classFiles.hasMoreElements()) {
1141 // retrieve the key and the corresponding classfile
1142 ClassFile classFile = (ClassFile) classFiles.nextElement();
1143 char[] filename = classFile.fileName();
1144 int length = filename.length;
1145 char[] relativeName = new char[length + 6];
1146 System.arraycopy(filename, 0, relativeName, 0, length);
1147 System.arraycopy(CLASS_FILE_EXTENSION, 0, relativeName, length, 6);
1148 CharOperation.replace(relativeName, '/', File.separatorChar);
1150 ClassFile.writeToDisk(
1151 generatePackagesStructure,
1153 new String(relativeName),
1154 classFile.getBytes());
1155 } catch (IOException e) {
1156 String fileName = destinationPath + new String(relativeName);
1157 e.printStackTrace();
1158 System.out.println(Main.bind("output.noClassFileCreated", fileName)); //$NON-NLS-1$
1160 exportedClassFilesCounter++;
1166 * Low-level API performing the actual compilation
1168 public void performCompilation() throws InvalidInputException {
1170 INameEnvironment environment = getLibraryAccess();
1171 Compiler batchCompiler =
1174 getHandlingPolicy(),
1176 getBatchRequestor(),
1177 getProblemFactory());
1178 CompilerOptions options = batchCompiler.options;
1180 // set the non-externally configurable options.
1181 options.setVerboseMode(verbose);
1182 options.produceReferenceInfo(produceRefInfo);
1183 batchCompiler.compile(getCompilationUnits());
1186 environment.cleanup();
1188 public void printUsage() {
1189 out.println(Main.bind("misc.usage", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$
1194 * Creates a NLS catalog for the given locale.
1196 public static void relocalize() {
1197 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1201 * Lookup the message with the given ID in this catalog
1203 public static String bind(String id) {
1204 return bind(id, (String[]) null);
1208 * Lookup the message with the given ID in this catalog and bind its
1209 * substitution locations with the given string values.
1211 public static String bind(String id, String[] bindings) {
1213 return "No message available"; //$NON-NLS-1$
1214 String message = null;
1216 message = bundle.getString(id);
1217 } catch (MissingResourceException e) {
1218 // If we got an exception looking for the message, fail gracefully by just returning
1219 // the id we were looking for. In most cases this is semi-informative so is not too bad.
1220 return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
1222 // for compatibility with MessageFormat which eliminates double quotes in original message
1223 char[] messageWithNoDoubleQuotes =
1224 CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
1225 message = new String(messageWithNoDoubleQuotes);
1227 if (bindings == null)
1230 int length = message.length();
1233 StringBuffer output = new StringBuffer(80);
1235 if ((end = message.indexOf('{', start)) > -1) {
1236 output.append(message.substring(start + 1, end));
1237 if ((start = message.indexOf('}', end)) > -1) {
1240 index = Integer.parseInt(message.substring(end + 1, start));
1241 output.append(bindings[index]);
1242 } catch (NumberFormatException nfe) {
1243 output.append(message.substring(end + 1, start + 1));
1244 } catch (ArrayIndexOutOfBoundsException e) {
1245 output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
1248 output.append(message.substring(end, length));
1252 output.append(message.substring(start + 1, length));
1256 return output.toString();
1260 * Lookup the message with the given ID in this catalog and bind its
1261 * substitution locations with the given string.
1263 public static String bind(String id, String binding) {
1264 return bind(id, new String[] { binding });
1268 * Lookup the message with the given ID in this catalog and bind its
1269 * substitution locations with the given strings.
1271 public static String bind(String id, String binding1, String binding2) {
1272 return bind(id, new String[] { binding1, binding2 });
1275 public String extractDestinationPathFromSourceFile(CompilationResult result) {
1276 ICompilationUnit compilationUnit = result.compilationUnit;
1277 if (compilationUnit != null) {
1278 char[] fileName = compilationUnit.getFileName();
1279 int lastIndex = CharOperation.lastIndexOf(java.io.File.separatorChar, fileName);
1280 if (lastIndex == -1) {
1281 return System.getProperty("user.dir"); //$NON-NLS-1$
1283 return new String(CharOperation.subarray(fileName, 0, lastIndex));
1285 return System.getProperty("user.dir"); //$NON-NLS-1$