first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / batch / Main.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.batch;
12
13 import java.io.ByteArrayInputStream;
14 import java.io.File;
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;
23 import java.util.Map;
24 import java.util.MissingResourceException;
25 import java.util.ResourceBundle;
26 import java.util.StringTokenizer;
27
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;
44
45 public class Main implements ProblemSeverities {
46
47         public boolean noWarn = false;
48
49         public PrintWriter out;
50         public boolean systemExitWhenFinished = true;
51         public boolean proceedOnError = false;
52
53         public boolean verbose = false;
54         public boolean produceRefInfo = false;
55         public boolean timer = false;
56         public boolean showProgress = false;
57         public long time = 0;
58         public long lineCount;
59         public boolean generatePackagesStructure;
60
61         public Hashtable options;
62         public String[] filenames;
63         public String[] encodings;
64         public String[] classpaths;
65         public String destinationPath;
66         public String log;
67         public int repetitions;
68         public int globalProblemsCount;
69         public int globalErrorsCount;
70         public int globalWarningsCount;
71         public int exportedClassFilesCounter;
72
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$
76
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$
81
82         static {
83                 relocalize();
84         }
85
86         public boolean proceed = true;
87
88         public Main(PrintWriter writer, boolean systemExitWhenFinished) {
89
90                 this.out = writer;
91                 this.systemExitWhenFinished = systemExitWhenFinished;
92                 exportedClassFilesCounter = 0;
93                 options = new Hashtable();
94                 options.put(
95                         CompilerOptions.OPTION_LocalVariableAttribute,
96                         CompilerOptions.DO_NOT_GENERATE);
97                 options.put(
98                         CompilerOptions.OPTION_LineNumberAttribute,
99                         CompilerOptions.DO_NOT_GENERATE);
100                 options.put(
101                         CompilerOptions.OPTION_SourceFileAttribute,
102                         CompilerOptions.DO_NOT_GENERATE);
103                 options.put(
104                         CompilerOptions.OPTION_PreserveUnusedLocal,
105                         CompilerOptions.OPTIMIZE_OUT);
106                 options.put(
107                         CompilerOptions.OPTION_ReportUnreachableCode,
108                         CompilerOptions.ERROR);
109                 options.put(CompilerOptions.OPTION_ReportInvalidImport, CompilerOptions.ERROR);
110                 options.put(
111                         CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
112                         CompilerOptions.WARNING);
113                 options.put(
114                         CompilerOptions.OPTION_ReportMethodWithConstructorName,
115                         CompilerOptions.WARNING);
116                 options.put(CompilerOptions.OPTION_ReportDeprecation, CompilerOptions.WARNING);
117                 options.put(
118                         CompilerOptions.OPTION_ReportHiddenCatchBlock,
119                         CompilerOptions.WARNING);
120                 options.put(CompilerOptions.OPTION_ReportUnusedLocal, CompilerOptions.IGNORE);
121                 options.put(
122                         CompilerOptions.OPTION_ReportUnusedParameter,
123                         CompilerOptions.IGNORE);
124                 options.put(
125                         CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
126                         CompilerOptions.IGNORE);
127                 options.put(
128                         CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
129                         CompilerOptions.IGNORE);
130                 options.put(
131                         CompilerOptions.OPTION_ReportAssertIdentifier,
132                         CompilerOptions.IGNORE);
133                 options.put(
134                         CompilerOptions.OPTION_Compliance,
135                         CompilerOptions.VERSION_1_3);
136                 options.put(
137                         CompilerOptions.OPTION_Source,
138                         CompilerOptions.VERSION_1_3);
139                 options.put(
140                         CompilerOptions.OPTION_TargetPlatform,
141                         CompilerOptions.VERSION_1_1);
142         }
143
144         /*
145          *  Low-level API performing the actual compilation
146          */
147         public boolean compile(String[] argv) {
148
149                 // decode command line arguments
150                 try {
151                         configure(argv);
152                         if (proceed) {
153                                 if (showProgress)
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;
159                                         lineCount = 0;
160
161                                         if (repetitions > 1) {
162                                                 out.flush();
163                                                 out.println(
164                                                         Main.bind(
165                                                                 "compile.repetition", //$NON-NLS-1$
166                                                                 String.valueOf(i + 1),
167                                                                 String.valueOf(repetitions)));
168                                         }
169                                         long startTime = System.currentTimeMillis();
170                                         // request compilation
171                                         performCompilation();
172                                         if (timer) {
173
174                                                 time = System.currentTimeMillis() - startTime;
175                                                 if (lineCount != 0) {
176                                                         out.println(
177                                                                 Main.bind(
178                                                                         "compile.instantTime",  //$NON-NLS-1$
179                                                                         new String[] {
180                                                                                 String.valueOf(lineCount),
181                                                                                 String.valueOf(time),
182                                                                                 String.valueOf((((int) ((lineCount * 10000.0) / time)) / 10.0))}));
183                                                 } else {
184                                                         out.println(Main.bind("compile.totalTime", String.valueOf(time))); //$NON-NLS-1$
185                                                 }
186                                         }
187                                         if (globalProblemsCount > 0) {
188                                                 if (globalProblemsCount == 1) {
189                                                         out.print(Main.bind("compile.oneProblem")); //$NON-NLS-1$
190                                                 } else {
191                                                         out.print(
192                                                                 Main.bind("compile.severalProblems", String.valueOf(globalProblemsCount)));     //$NON-NLS-1$
193                                                 }
194                                                 out.print(" ("); //$NON-NLS-1$
195                                                 if (globalErrorsCount > 0) {
196                                                         if (globalErrorsCount == 1) {
197                                                                 out.print(Main.bind("compile.oneError")); //$NON-NLS-1$
198                                                         } else {
199                                                                 out.print(
200                                                                         Main.bind("compile.severalErrors", String.valueOf(globalErrorsCount)));         //$NON-NLS-1$
201                                                         }
202                                                 }
203                                                 if (globalWarningsCount > 0) {
204                                                         if (globalErrorsCount > 0) {
205                                                                 out.print(", "); //$NON-NLS-1$
206                                                         }
207                                                         if (globalWarningsCount == 1) {
208                                                                 out.print(Main.bind("compile.oneWarning")); //$NON-NLS-1$
209                                                         } else {
210                                                                 out.print(
211                                                                         Main.bind("compile.severalWarnings", String.valueOf(globalWarningsCount)));     //$NON-NLS-1$
212                                                         }
213                                                 }
214                                                 out.println(")"); //$NON-NLS-1$
215                                         }
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$
220                                                 } else {
221                                                         out.print(
222                                                                 Main.bind(
223                                                                         "compile.severalClassFilesGenerated", //$NON-NLS-1$
224                                                                         String.valueOf(exportedClassFilesCounter)));
225                                                 }
226                                         }
227                                 }
228                                 if (showProgress)
229                                         System.out.println();
230                         }
231                         if (systemExitWhenFinished) {
232                                 out.flush();
233                                 System.exit(globalErrorsCount > 0 ? -1 : 0);
234                         }
235                 } catch (InvalidInputException e) {
236                         out.println(e.getMessage());
237                         out.println("------------------------"); //$NON-NLS-1$
238                         printUsage();
239                         if (systemExitWhenFinished) {
240                                 System.exit(-1);
241                         }
242                 } catch (ThreadDeath e) { // do not stop this one
243                         throw e;
244                 } catch (Throwable e) { // internal compiler error
245                         if (systemExitWhenFinished) {
246                                 out.flush();
247                                 if (this.log != null) {
248                                         out.close();
249                                 }
250                                 System.exit(-1);
251                         }
252                         //e.printStackTrace();
253                 } finally {
254                         out.flush();
255                         if (this.log != null) {
256                                 out.close();
257                         }
258                 }
259                 if (globalErrorsCount == 0){
260                         return true;
261                 } else {
262                         return false;
263                 }
264         }
265
266         /*
267          * Internal IDE API
268          */
269         public static boolean compile(String commandLine) {
270
271                 return compile(commandLine, new PrintWriter(System.out));
272         }
273
274         /*
275          * Internal IDE API for test harness purpose
276          */
277         public static boolean compile(String commandLine, PrintWriter writer) {
278
279                 return new Main(writer, false).compile(tokenize(commandLine));
280         }
281
282         public static String[] tokenize(String commandLine) {
283
284                 int count = 0;
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;
290
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()) {
297                         lastToken = token;
298                         token = tokenizer.nextToken();
299
300                         if (token.equals(" ")) { //$NON-NLS-1$
301                                 if (insideQuotes) {
302                                         arguments[count - 1] += token;
303                                         startNewToken = false;
304                                 } else {
305                                         startNewToken = true;
306                                 }
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$
312                                 }
313                                 insideQuotes = !insideQuotes;
314                                 startNewToken = false;
315                         } else {
316                                 if (insideQuotes) {
317                                         arguments[count - 1] += token;
318                                 } else {
319                                         if (token.length() > 0 && !startNewToken) {
320                                                 arguments[count - 1] += token;
321                                         } else {
322                                                 if (count == arguments.length)
323                                                         System.arraycopy(arguments, 0, (arguments = new String[count * 2]), 0, count);
324                                                 arguments[count++] = token;
325                                         }
326                                 }
327                                 startNewToken = false;
328                         }
329                 }
330                 System.arraycopy(arguments, 0, arguments = new String[count], 0, count);
331                 return arguments;
332         }
333
334         /*
335         Decode the command line arguments 
336          */
337         public void configure(String[] argv) throws InvalidInputException {
338                 
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;
352                 int pathCount = 0;
353                 int index = -1, filesCount = 0, argCount = argv.length;
354                 int mode = Default;
355                 repetitions = 0;
356                 boolean versionIDRequired = false;
357                 boolean printUsageRequired = false;
358
359                 boolean didSpecifyCompliance = false;
360                 boolean didSpecifySourceLevel = false;
361                 boolean didSpecifyDefaultEncoding = false;
362                 boolean didSpecifyTarget = false;
363
364                 String customEncoding = null;
365                 String currentArg = ""; //$NON-NLS-1$
366
367                 while (++index < argCount) {
368
369                         if (customEncoding != null) {
370                                 throw new InvalidInputException(
371                                         Main.bind("configure.unexpectedCustomEncoding", currentArg, customEncoding)); //$NON-NLS-1$
372                         }
373
374                         currentArg = argv[index].trim();
375
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$
389                                                 }
390                                         }
391                                         currentArg = currentArg.substring(0, encodingStart - 1);
392                                 }
393                         }
394
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;
401                                         System.arraycopy(
402                                                 filenames,
403                                                 0,
404                                                 (filenames = new String[length + argCount - index]),
405                                                 0,
406                                                 length);
407                                         System.arraycopy(
408                                                 encodings,
409                                                 0,
410                                                 (encodings = new String[length + argCount - index]),
411                                                 0,
412                                                 length);
413                                 }
414                                 filenames[filesCount] = currentArg;
415                                 encodings[filesCount++] = customEncoding;
416                                 customEncoding = null;
417                                 mode = Default;
418                                 continue;
419                         }
420                         if (currentArg.equals("-log")) { //$NON-NLS-1$
421                                 if (log != null)
422                                         throw new InvalidInputException(
423                                                 Main.bind("configure.duplicateLog", currentArg)); //$NON-NLS-1$
424                                 mode = InsideLog;
425                                 continue;
426                         }
427                         if (currentArg.equals("-repeat")) { //$NON-NLS-1$
428                                 if (repetitions > 0)
429                                         throw new InvalidInputException(
430                                                 Main.bind("configure.duplicateRepeat", currentArg)); //$NON-NLS-1$
431                                 mode = InsideRepetition;
432                                 continue;
433                         }
434                         if (currentArg.equals("-source")) { //$NON-NLS-1$
435                                 mode = InsideSource;
436                                 didSpecifySourceLevel = true;
437                                 continue;
438                         }
439                         if (currentArg.equals("-encoding")) { //$NON-NLS-1$
440                                 mode = InsideDefaultEncoding;
441                                 continue;
442                         }
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$
447                                 }
448                                 didSpecifyCompliance = true;
449                                 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3);
450                                 mode = Default;
451                                 continue;
452                         }
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$
457                                 }
458                                 didSpecifyCompliance = true;
459                                 options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_4);
460                                 mode = Default;
461                                 continue;
462                         }
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;
469                                 continue;
470                         }
471                         if (currentArg.equals("-classpath") //$NON-NLS-1$
472                                 || currentArg.equals("-cp")) { //$NON-NLS-1$ //$NON-NLS-2$
473                                 if (pathCount > 0)
474                                         throw new InvalidInputException(
475                                                 Main.bind("configure.duplicateClasspath", currentArg)); //$NON-NLS-1$
476                                 classpaths = new String[DEFAULT_SIZE_CLASSPATH];
477                                 mode = InsideClasspath;
478                                 continue;
479                         }
480                         if (currentArg.equals("-progress")) { //$NON-NLS-1$
481                                 mode = Default;
482                                 showProgress = true;
483                                 continue;
484                         }
485                         if (currentArg.equals("-proceedOnError")) { //$NON-NLS-1$
486                                 mode = Default;
487                                 proceedOnError = true;
488                                 continue;
489                         }
490                         if (currentArg.equals("-time")) { //$NON-NLS-1$
491                                 mode = Default;
492                                 timer = true;
493                                 continue;
494                         }
495                         if (currentArg.equals("-version") //$NON-NLS-1$
496                                 || currentArg.equals("-v")) { //$NON-NLS-1$ //$NON-NLS-2$
497                                 versionIDRequired = true;
498                                 continue;
499                         }
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);
506                                 continue;
507                         }
508                         if (currentArg.equals("-help")) { //$NON-NLS-1$
509                                 printUsageRequired = true;
510                                 continue;
511                         }
512                         if (currentArg.equals("-noImportError")) { //$NON-NLS-1$
513                                 mode = Default;
514                                 options.put(
515                                         CompilerOptions.OPTION_ReportInvalidImport,
516                                         CompilerOptions.WARNING);
517                                 continue;
518                         }
519                         if (currentArg.equals("-noExit")) { //$NON-NLS-1$
520                                 mode = Default;
521                                 systemExitWhenFinished = false;
522                                 continue;
523                         }
524                         if (currentArg.equals("-verbose")) { //$NON-NLS-1$
525                                 mode = Default;
526                                 verbose = true;
527                                 continue;
528                         }
529                         if (currentArg.equals("-referenceInfo")) { //$NON-NLS-1$
530                                 mode = Default;
531                                 produceRefInfo = true;
532                                 continue;
533                         }
534                         if (currentArg.startsWith("-g")) { //$NON-NLS-1$
535                                 mode = Default;
536                                 String debugOption = currentArg;
537                                 int length = currentArg.length();
538                                 if (length == 2) {
539                                         options.put(
540                                                 CompilerOptions.OPTION_LocalVariableAttribute,
541                                                 CompilerOptions.GENERATE);
542                                         options.put(
543                                                 CompilerOptions.OPTION_LineNumberAttribute,
544                                                 CompilerOptions.GENERATE);
545                                         options.put(
546                                                 CompilerOptions.OPTION_SourceFileAttribute,
547                                                 CompilerOptions.GENERATE);
548                                         continue;
549                                 }
550                                 if (length > 3) {
551                                         options.put(
552                                                 CompilerOptions.OPTION_LocalVariableAttribute,
553                                                 CompilerOptions.DO_NOT_GENERATE);
554                                         options.put(
555                                                 CompilerOptions.OPTION_LineNumberAttribute,
556                                                 CompilerOptions.DO_NOT_GENERATE);
557                                         options.put(
558                                                 CompilerOptions.OPTION_SourceFileAttribute,
559                                                 CompilerOptions.DO_NOT_GENERATE);
560                                         if (length == 7 && debugOption.equals("-g:none")) //$NON-NLS-1$
561                                                 continue;
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$
567                                                         options.put(
568                                                                 CompilerOptions.OPTION_LocalVariableAttribute,
569                                                                 CompilerOptions.GENERATE);
570                                                 } else if (token.equals("lines")) { //$NON-NLS-1$
571                                                         options.put(
572                                                                 CompilerOptions.OPTION_LineNumberAttribute,
573                                                                 CompilerOptions.GENERATE);
574                                                 } else if (token.equals("source")) { //$NON-NLS-1$
575                                                         options.put(
576                                                                 CompilerOptions.OPTION_SourceFileAttribute,
577                                                                 CompilerOptions.GENERATE);
578                                                 } else {
579                                                         throw new InvalidInputException(
580                                                                 Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
581                                                         //$NON-NLS-1$
582                                                 }
583                                         }
584                                         continue;
585                                 }
586                                 throw new InvalidInputException(
587                                         Main.bind("configure.invalidDebugOption", debugOption)); //$NON-NLS-1$
588                         }
589                         if (currentArg.startsWith("-nowarn")) { //$NON-NLS-1$
590                                 noWarnOptionInUse = true;
591                                 noWarn = true;
592                                 if (warnOptionInUse)
593                                         throw new InvalidInputException(
594                                                 Main.bind("configure.duplicateWarningConfiguration")); //$NON-NLS-1$
595                                 mode = Default;
596                                 continue;
597                         }
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$
603                                 mode = Default;
604                                 String warningOption = currentArg;
605                                 int length = currentArg.length();
606                                 if (length == 10 && warningOption.equals("-warn:none")) { //$NON-NLS-1$
607                                         noWarn = true;
608                                         continue;
609                                 }
610                                 if (length < 6)
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;
616
617                                 options.put(
618                                         CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
619                                         CompilerOptions.IGNORE);
620                                 options.put(
621                                         CompilerOptions.OPTION_ReportMethodWithConstructorName,
622                                         CompilerOptions.IGNORE);
623                                 options.put(
624                                         CompilerOptions.OPTION_ReportDeprecation, 
625                                         CompilerOptions.IGNORE);
626                                 options.put(
627                                         CompilerOptions.OPTION_ReportHiddenCatchBlock,
628                                         CompilerOptions.IGNORE);
629                                 options.put(
630                                         CompilerOptions.OPTION_ReportUnusedLocal, 
631                                         CompilerOptions.IGNORE);
632                                 options.put(
633                                         CompilerOptions.OPTION_ReportUnusedParameter,
634                                         CompilerOptions.IGNORE);
635                                 options.put(
636                                         CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
637                                         CompilerOptions.IGNORE);
638                                 options.put(
639                                         CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
640                                         CompilerOptions.IGNORE);
641                                 options.put(
642                                         CompilerOptions.OPTION_ReportAssertIdentifier,
643                                         CompilerOptions.IGNORE);
644                                 options.put(
645                                         CompilerOptions.OPTION_ReportUnusedImport,
646                                         CompilerOptions.IGNORE);
647
648                                 while (tokenizer.hasMoreTokens()) {
649                                         String token = tokenizer.nextToken();
650                                         tokenCounter++;
651                                         if (token.equals("constructorName")) { //$NON-NLS-1$
652                                                 options.put(
653                                                         CompilerOptions.OPTION_ReportMethodWithConstructorName,
654                                                         CompilerOptions.WARNING);
655                                         } else if (token.equals("packageDefaultMethod")) { //$NON-NLS-1$
656                                                 options.put(
657                                                         CompilerOptions.OPTION_ReportOverridingPackageDefaultMethod,
658                                                         CompilerOptions.WARNING);
659                                         } else if (token.equals("maskedCatchBlocks")) { //$NON-NLS-1$
660                                                 options.put(
661                                                         CompilerOptions.OPTION_ReportHiddenCatchBlock,
662                                                         CompilerOptions.WARNING);
663                                         } else if (token.equals("deprecation")) { //$NON-NLS-1$
664                                                 options.put(
665                                                         CompilerOptions.OPTION_ReportDeprecation, 
666                                                         CompilerOptions.WARNING);
667                                         } else if (token.equals("unusedLocals")) { //$NON-NLS-1$
668                                                 options.put(
669                                                         CompilerOptions.OPTION_ReportUnusedLocal, 
670                                                         CompilerOptions.WARNING);
671                                         } else if (token.equals("unusedArguments")) { //$NON-NLS-1$
672                                                 options.put(
673                                                         CompilerOptions.OPTION_ReportUnusedParameter,
674                                                         CompilerOptions.WARNING);
675                                         } else if (token.equals("unusedImports")) { //$NON-NLS-1$
676                                                 options.put(
677                                                         CompilerOptions.OPTION_ReportUnusedImport,
678                                                         CompilerOptions.WARNING);
679                                         } else if (token.equals("syntheticAccess")) { //$NON-NLS-1$
680                                                 options.put(
681                                                         CompilerOptions.OPTION_ReportSyntheticAccessEmulation,
682                                                         CompilerOptions.WARNING);
683                                         } else if (token.equals("nls")) { //$NON-NLS-1$
684                                                 options.put(
685                                                         CompilerOptions.OPTION_ReportNonExternalizedStringLiteral,
686                                                         CompilerOptions.WARNING);
687                                         } else if (token.equals("assertIdentifier")) { //$NON-NLS-1$
688                                                 options.put(
689                                                         CompilerOptions.OPTION_ReportAssertIdentifier,
690                                                         CompilerOptions.WARNING);
691                                         } else {
692                                                 throw new InvalidInputException(Main.bind("configure.invalidWarning", token)); //$NON-NLS-1$
693                                         }
694                                 }
695                                 if (tokenCounter == 0)
696                                         throw new InvalidInputException(
697                                                 Main.bind("configure.invalidWarningOption", currentArg)); //$NON-NLS-1$
698                                 continue;
699                         }
700                         if (currentArg.equals("-target")) { //$NON-NLS-1$
701                                 didSpecifyTarget = true;
702                                 mode = TargetSetting;
703                                 continue;
704                         }
705                         if (currentArg.equals("-preserveAllLocals")) { //$NON-NLS-1$
706                                 options.put(
707                                         CompilerOptions.OPTION_PreserveUnusedLocal,
708                                         CompilerOptions.PRESERVE);
709                                 continue;
710                         }
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);
720                                 } else {
721                                         throw new InvalidInputException(Main.bind("configure.targetJDK", currentArg)); //$NON-NLS-1$
722                                 }
723                                 mode = Default;
724                                 continue;
725                         }
726                         if (mode == InsideLog) {
727                                 log = currentArg;
728                                 mode = Default;
729                                 continue;
730                         }
731                         if (mode == InsideRepetition) {
732                                 try {
733                                         repetitions = Integer.parseInt(currentArg);
734                                         if (repetitions <= 0) {
735                                                 throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$
736                                         }
737                                 } catch (NumberFormatException e) {
738                                         throw new InvalidInputException(Main.bind("configure.repetition", currentArg)); //$NON-NLS-1$
739                                 }
740                                 mode = Default;
741                                 continue;
742                         }
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);
748                                 } else {
749                                         throw new InvalidInputException(Main.bind("configure.source", currentArg)); //$NON-NLS-1$
750                                 }
751                                 mode = Default;
752                                 continue;
753                         }
754                         if (mode == InsideDefaultEncoding) {
755                                 if (didSpecifyDefaultEncoding) {
756                                         throw new InvalidInputException(
757                                                 Main.bind("configure.duplicateDefaultEncoding", currentArg)); //$NON-NLS-1$
758                                 }
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$
764                                 }
765                                 options.put(CompilerOptions.OPTION_Encoding, currentArg);
766                                 didSpecifyDefaultEncoding = true;
767                                 mode = Default;
768                                 continue;
769                         }
770                         if (mode == InsideDestinationPath) {
771                                 destinationPath = currentArg;
772                                 mode = Default;
773                                 continue;
774                         }
775                         if (mode == InsideClasspath) {
776                                 StringTokenizer tokenizer = new StringTokenizer(currentArg, File.pathSeparator);
777                                 while (tokenizer.hasMoreTokens()) {
778                                         int length;
779                                         if ((length = classpaths.length) <= pathCount) {
780                                                 System.arraycopy(
781                                                         classpaths,
782                                                         0,
783                                                         (classpaths = new String[length * 2]),
784                                                         0,
785                                                         length);
786                                         }
787                                         classpaths[pathCount++] = tokenizer.nextToken();
788                                 }
789                                 mode = Default;
790                                 continue;
791                         }
792                         //default is input directory
793                         currentArg = currentArg.replace('/', File.separatorChar);
794                         if (currentArg.endsWith(File.separator))
795                                 currentArg =
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();
802                         try {
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$
806                         }
807                         if (filenames != null) {
808                                 // some source files were specified explicitly
809                                 String results[] = finder.resultFiles;
810                                 int length = results.length;
811                                 System.arraycopy(
812                                         filenames,
813                                         0,
814                                         (filenames = new String[length + filesCount]),
815                                         0,
816                                         filesCount);
817                                 System.arraycopy(
818                                         encodings,
819                                         0,
820                                         (encodings = new String[length + filesCount]),
821                                         0,
822                                         filesCount);
823                                 System.arraycopy(results, 0, filenames, filesCount, length);
824                                 for (int i = 0; i < length; i++) {
825                                         encodings[filesCount + i] = customEncoding;
826                                 }
827                                 filesCount += length;
828                                 customEncoding = null;
829                         } else {
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;
835                                 }
836                                 customEncoding = null;
837                         }
838                         mode = Default;
839                         continue;
840                 }
841
842                 if (noWarn) {
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))
848                                         continue;
849                                 if (!(entry.getValue() instanceof String))
850                                         continue;
851                                 if (((String) entry.getValue()).equals(CompilerOptions.WARNING)) {
852                                         options.put((String) entry.getKey(), CompilerOptions.IGNORE);
853                                 }
854                         }
855                 }
856                 /*
857                  * Standalone options
858                  */
859                 if (versionIDRequired) {
860                         out.println(Main.bind("configure.version", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$
861                         out.println();
862                         proceed = false;
863                         return;
864                 }
865
866                 if (printUsageRequired) {
867                         printUsage();
868                         proceed = false;
869                         return;
870                 }
871
872                 if (filesCount != 0)
873                         System.arraycopy(
874                                 filenames,
875                                 0,
876                                 (filenames = new String[filesCount]),
877                                 0,
878                                 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$
884                         }
885                         StringTokenizer tokenizer = new StringTokenizer(classProp, File.pathSeparator);
886                         classpaths = new String[tokenizer.countTokens()];
887                         while (tokenizer.hasMoreTokens()) {
888                                 classpaths[pathCount++] = tokenizer.nextToken();
889                         }
890                 }
891
892                 if (classpaths == null)
893                         classpaths = new String[0];
894                 System.arraycopy(
895                         classpaths,
896                         0,
897                         (classpaths = new String[pathCount]),
898                         0,
899                         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$
904                 }
905                 if (destinationPath == null) {
906                         generatePackagesStructure = false;
907                 } else if ("none".equals(destinationPath)) { //$NON-NLS-1$
908                         destinationPath = null;
909                 }
910
911                 if (filenames == null)
912                         throw new InvalidInputException(Main.bind("configure.noSource")); //$NON-NLS-1$
913
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);
918                                 } else {
919                                         options.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_3);
920                                 }
921                 }
922                 String compliance = (String)options.get(CompilerOptions.OPTION_Compliance);
923                 if (CompilerOptions.VERSION_1_4.equals(compliance)){
924                         
925                         // default 1.4 settings
926                         if (!didSpecifySourceLevel){
927                                 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4);
928                         }
929                         if (!didSpecifyTarget){
930                                 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_4);
931                         }
932                 } else if (CompilerOptions.VERSION_1_3.equals(compliance)){
933
934                         // default 1.4 settings
935                         if (!didSpecifySourceLevel){
936                                 options.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_3);
937                         }
938                         if (!didSpecifyTarget){
939                                 options.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_1_1);
940                         }
941                 }
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$
946                 }
947                 
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$
952                 }
953
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$
958                 }
959                 
960                 if (log != null) {
961                         try {
962                                 out = new PrintWriter(new FileOutputStream(log, false));
963                         } catch (IOException e) {
964                                 throw new InvalidInputException(Main.bind("configure.cannotOpenLog")); //$NON-NLS-1$
965                         }
966                 } else {
967                         showProgress = false;
968                 }
969
970                 if (repetitions == 0) {
971                         repetitions = 1;
972                 }
973         }
974         public Map getOptions() {
975                 return this.options;
976         }
977         /*
978          * Answer the component to which will be handed back compilation results from the compiler
979          */
980         public ICompilerRequestor getBatchRequestor() {
981                 return new ICompilerRequestor() {
982                         int lineDelta = 0;
983                         public void acceptResult(CompilationResult compilationResult) {
984                                 if (compilationResult.lineSeparatorPositions != null) {
985                                         int unitLineCount = compilationResult.lineSeparatorPositions.length;
986                                         lineCount += unitLineCount;
987                                         lineDelta += unitLineCount;
988                                         if (showProgress
989                                                 && lineDelta > 2000) { // in -log mode, dump a dot every 2000 lines compiled
990                                                 System.out.print('.');
991                                                 lineDelta = 0;
992                                         }
993                                 }
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$
1003                                                         out.print(
1004                                                                 globalProblemsCount
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++;
1011                                                         } else {
1012                                                                 globalWarningsCount++;
1013                                                         }
1014                                                         out.print(" "); //$NON-NLS-1$
1015                                                         out.print(
1016                                                                 Main.bind("requestor.in", new String(problems[i].getOriginatingFileName()))); //$NON-NLS-1$
1017                                                         try {
1018                                                                 out.println(
1019                                                                         ((DefaultProblem) problems[i]).errorReportSource(
1020                                                                                 compilationResult.compilationUnit));
1021                                                                 out.println(problems[i].getMessage());
1022                                                         } catch (Exception e) {
1023                                                                 out.println(
1024                                                                         Main.bind("requestor.notRetrieveErrorMessage", problems[i].toString())); //$NON-NLS-1$
1025                                                         }
1026                                                         out.println("----------"); //$NON-NLS-1$
1027                                                         if (problems[i].isError())
1028                                                                 localErrorCount++;
1029                                                 }
1030                                         };
1031                                         // exit?
1032                                         if (systemExitWhenFinished && !proceedOnError && (localErrorCount > 0)) {
1033                                                 out.flush();
1034                                                 System.exit(-1);
1035                                         }
1036                                 }
1037                                 outputClassFiles(compilationResult);
1038                         }
1039                 };
1040         }
1041         /*
1042          *  Build the set of compilation source units
1043          */
1044         public CompilationUnit[] getCompilationUnits()
1045                 throws InvalidInputException {
1046                 int fileCount = filenames.length;
1047                 CompilationUnit[] units = new CompilationUnit[fileCount];
1048                 HashtableOfObject knownFileNames = new HashtableOfObject(fileCount);
1049
1050                 String defaultEncoding = (String) options.get(CompilerOptions.OPTION_Encoding);
1051                 if ("".equals(defaultEncoding)) //$NON-NLS-1$
1052                         defaultEncoding = null; //$NON-NLS-1$
1053
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$
1058                         } else {
1059                                 knownFileNames.put(charName, charName);
1060                         }
1061                         File file = new File(filenames[i]);
1062                         if (!file.exists())
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);
1068                 }
1069                 return units;
1070         }
1071         /*
1072          *  Low-level API performing the actual compilation
1073          */
1074         public IErrorHandlingPolicy getHandlingPolicy() {
1075
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() {
1079                                 return false;
1080                         }
1081                         public boolean proceedOnErrors() {
1082                                 return proceedOnError; // stop if there are some errors 
1083                         }
1084                 };
1085         }
1086         /*
1087          *  Low-level API performing the actual compilation
1088          */
1089         public FileSystem getLibraryAccess() {
1090
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);
1095         }
1096         /*
1097          *  Low-level API performing the actual compilation
1098          */
1099         public IProblemFactory getProblemFactory() {
1100                 return new DefaultProblemFactory(Locale.getDefault());
1101         }
1102         /*
1103          * External API
1104          */
1105
1106         public static void main(String[] argv) {
1107                 new Main(new PrintWriter(System.out), true).compile(argv);
1108         }
1109         // Dump classfiles onto disk for all compilation units that where successfull.
1110
1111         public void outputClassFiles(CompilationResult unitResult) {
1112
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);
1126                                         try {
1127                                                 ClassFile.writeToDisk(
1128                                                         generatePackagesStructure,
1129                                                         destinationPath,
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$
1136                                         }
1137                                         exportedClassFilesCounter++;
1138                                 }
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);
1149                                         try {
1150                                                 ClassFile.writeToDisk(
1151                                                         generatePackagesStructure,
1152                                                         destinationPath,
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$
1159                                         }
1160                                         exportedClassFilesCounter++;
1161                                 }
1162                         }
1163                 }
1164         }
1165         /*
1166          *  Low-level API performing the actual compilation
1167          */
1168         public void performCompilation() throws InvalidInputException {
1169
1170                 INameEnvironment environment = getLibraryAccess();
1171                 Compiler batchCompiler =
1172                         new Compiler(
1173                                 environment,
1174                                 getHandlingPolicy(),
1175                                 getOptions(),
1176                                 getBatchRequestor(),
1177                                 getProblemFactory());
1178                 CompilerOptions options = batchCompiler.options;
1179
1180                 // set the non-externally configurable options.
1181                 options.setVerboseMode(verbose);
1182                 options.produceReferenceInfo(produceRefInfo);
1183                 batchCompiler.compile(getCompilationUnits());
1184
1185                 // cleanup
1186                 environment.cleanup();
1187         }
1188         public void printUsage() {
1189                 out.println(Main.bind("misc.usage", Main.bind("compiler.version"))); //$NON-NLS-1$ //$NON-NLS-2$
1190                 out.flush();
1191         }
1192
1193         /**
1194          * Creates a NLS catalog for the given locale.
1195          */
1196         public static void relocalize() {
1197                 bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
1198         }
1199
1200         /**
1201          * Lookup the message with the given ID in this catalog 
1202          */
1203         public static String bind(String id) {
1204                 return bind(id, (String[]) null);
1205         }
1206
1207         /**
1208          * Lookup the message with the given ID in this catalog and bind its
1209          * substitution locations with the given string values.
1210          */
1211         public static String bind(String id, String[] bindings) {
1212                 if (id == null)
1213                         return "No message available"; //$NON-NLS-1$
1214                 String message = null;
1215                 try {
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$
1221                 }
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);
1226
1227                 if (bindings == null)
1228                         return message;
1229
1230                 int length = message.length();
1231                 int start = -1;
1232                 int end = length;
1233                 StringBuffer output = new StringBuffer(80);
1234                 while (true) {
1235                         if ((end = message.indexOf('{', start)) > -1) {
1236                                 output.append(message.substring(start + 1, end));
1237                                 if ((start = message.indexOf('}', end)) > -1) {
1238                                         int index = -1;
1239                                         try {
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$
1246                                         }
1247                                 } else {
1248                                         output.append(message.substring(end, length));
1249                                         break;
1250                                 }
1251                         } else {
1252                                 output.append(message.substring(start + 1, length));
1253                                 break;
1254                         }
1255                 }
1256                 return output.toString();
1257         }
1258
1259         /**
1260          * Lookup the message with the given ID in this catalog and bind its
1261          * substitution locations with the given string.
1262          */
1263         public static String bind(String id, String binding) {
1264                 return bind(id, new String[] { binding });
1265         }
1266
1267         /**
1268          * Lookup the message with the given ID in this catalog and bind its
1269          * substitution locations with the given strings.
1270          */
1271         public static String bind(String id, String binding1, String binding2) {
1272                 return bind(id, new String[] { binding1, binding2 });
1273         }
1274
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$
1282                         }
1283                         return new String(CharOperation.subarray(fileName, 0, lastIndex));
1284                 }
1285                 return System.getProperty("user.dir"); //$NON-NLS-1$
1286         }
1287
1288 }