1 /*
2  * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.tools.javac;
27 
28 import sun.tools.java.*;
29 import sun.tools.util.CommandLine;
30 // JCOV
31 import sun.tools.asm.Assembler;
32 // end JCOV
33 
34 import java.util.*;
35 import java.io.*;
36 import java.text.MessageFormat;
37 
38 /**
39  * Main program of the Java compiler
40  *
41  * WARNING: The contents of this source file are not part of any
42  * supported API.  Code that depends on them does so at its own risk:
43  * they are subject to change or removal without notice.
44  *
45  * @deprecated As of J2SE 1.3, the preferred way to compile Java
46  * language sources is by using the new compiler,
47  * com.sun.tools.javac.Main.
48  */
49 @Deprecated
50 public
51 class Main implements Constants {
52     /**
53      * Name of the program.
54      */
55     String program;
56 
57     /**
58      * The stream where error message are printed.
59      */
60     OutputStream out;
61 
62     /**
63      * Constructor.
64      */
Main(OutputStream out, String program)65     public Main(OutputStream out, String program) {
66         this.out = out;
67         this.program = program;
68     }
69 
70     /**
71      * Exit status.
72      * We introduce a separate integer status variable, and do not alter the
73      * convention that 'compile' returns a boolean true upon a successful
74      * compilation with no errors.  (JavaTest relies on this.)
75      */
76 
77     public static final int EXIT_OK = 0;        // Compilation completed with no errors.
78     public static final int EXIT_ERROR = 1;     // Compilation completed but reported errors.
79     public static final int EXIT_CMDERR = 2;    // Bad command-line arguments and/or switches.
80     public static final int EXIT_SYSERR = 3;    // System error or resource exhaustion.
81     public static final int EXIT_ABNORMAL = 4;  // Compiler terminated abnormally.
82 
83     private int exitStatus;
84 
getExitStatus()85     public int getExitStatus() {
86         return exitStatus;
87     }
88 
compilationPerformedSuccessfully()89     public boolean compilationPerformedSuccessfully() {
90         return exitStatus == EXIT_OK || exitStatus == EXIT_ERROR;
91     }
92 
compilationReportedErrors()93     public boolean compilationReportedErrors () {
94         return exitStatus != EXIT_OK;
95     }
96 
97     /**
98      * Output a message.
99      */
output(String msg)100     private void output(String msg) {
101         PrintStream out =
102             this.out instanceof PrintStream ? (PrintStream)this.out
103                                             : new PrintStream(this.out, true);
104         out.println(msg);
105     }
106 
107     /**
108      * Top level error message.  This method is called when the
109      * environment could not be set up yet.
110      */
error(String msg)111     private void error(String msg) {
112         exitStatus = EXIT_CMDERR;
113         output(getText(msg));
114     }
115 
error(String msg, String arg1)116     private void error(String msg, String arg1) {
117         exitStatus = EXIT_CMDERR;
118         output(getText(msg, arg1));
119     }
120 
error(String msg, String arg1, String arg2)121     private void error(String msg, String arg1, String arg2) {
122         exitStatus = EXIT_CMDERR;
123         output(getText(msg, arg1, arg2));
124     }
125 
126     /**
127      * Print usage message and make exit status an error.
128      * Note: 'javac' invoked without any arguments is considered
129      * be an error.
130      */
usage_error()131     public void usage_error() {
132         error("main.usage", program);
133     }
134 
135     private static ResourceBundle messageRB;
136 
137     /**
138      * Initialize ResourceBundle
139      */
initResource()140     static void initResource() {
141         try {
142             messageRB =
143                 ResourceBundle.getBundle("sun.tools.javac.resources.javac");
144         } catch (MissingResourceException e) {
145             throw new Error("Fatal: Resource for javac is missing");
146         }
147     }
148 
149     /**
150      * get and format message string from resource
151      */
getText(String key)152     public static String getText(String key) {
153         return getText(key, (String)null);
154     }
155 
getText(String key, int num)156     public static String getText(String key, int num) {
157         return getText(key, Integer.toString(num));
158     }
159 
getText(String key, String fixed)160     public static String getText(String key, String fixed) {
161         return getText(key, fixed, null);
162     }
163 
getText(String key, String fixed1, String fixed2)164     public static String getText(String key, String fixed1, String fixed2) {
165         return getText(key, fixed1, fixed2, null);
166     }
167 
getText(String key, String fixed1, String fixed2, String fixed3)168     public static String getText(String key, String fixed1,
169                                  String fixed2, String fixed3) {
170         if (messageRB == null) {
171             initResource();
172         }
173         try {
174             String message = messageRB.getString(key);
175             return MessageFormat.format(message, fixed1, fixed2, fixed3);
176         } catch (MissingResourceException e) {
177             if (fixed1 == null)  fixed1 = "null";
178             if (fixed2 == null)  fixed2 = "null";
179             if (fixed3 == null)  fixed3 = "null";
180             String message = "JAVAC MESSAGE FILE IS BROKEN: key={0}, arguments={1}, {2}, {3}";
181             return MessageFormat.format(message, key, fixed1, fixed2, fixed3);
182         }
183     }
184 
185     // What major and minor version numbers to use for the -target flag.
186     // This should grow every time the minor version number accepted by
187     // the VM is incremented.
188     private static final String[] releases =      { "1.1", "1.2", "1.3", "1.4" };
189     private static final short[] majorVersions =  {    45,    46,    47,    48 };
190     private static final short[] minorVersions =  {     3,     0,     0,     0 };
191 
192     /**
193      * Run the compiler
194      */
195     @SuppressWarnings("fallthrough")
compile(String argv[])196     public synchronized boolean compile(String argv[]) {
197         String sourcePathArg = null;
198         String classPathArg = null;
199         String sysClassPathArg = null;
200         boolean verbosePath = false;
201 
202         String targetArg = null;
203         short majorVersion = JAVA_DEFAULT_VERSION;
204         short minorVersion = JAVA_DEFAULT_MINOR_VERSION;
205 
206         File destDir = null;
207 //JCOV
208         File covFile = null;
209         String optJcov = "-Xjcov";
210         String optJcovFile = "-Xjcov:file=";
211 //end JCOV
212         int flags = F_WARNINGS | F_DEBUG_LINES | F_DEBUG_SOURCE;
213         long tm = System.currentTimeMillis();
214         Vector<String> v = new Vector<>();
215         boolean nowrite = false;
216         String props = null;
217         String encoding = null;
218 
219         // These flags are used to make sure conflicting -O and -g
220         // options aren't given.
221         String prior_g = null;
222         String prior_O = null;
223 
224         exitStatus = EXIT_OK;
225 
226         // Pre-process command line for @file arguments
227         try {
228             argv = CommandLine.parse(argv);
229         } catch (FileNotFoundException e) {
230             error("javac.err.cant.read", e.getMessage());
231             System.exit(1);
232         } catch (IOException e) {
233             e.printStackTrace();
234             System.exit(1);
235         }
236 
237         // Parse arguments
238         for (int i = 0 ; i < argv.length ; i++) {
239             if (argv[i].equals("-g")) {
240                 if (prior_g!=null && !(prior_g.equals("-g")))
241                    error("main.conflicting.options", prior_g, "-g");
242                 prior_g = "-g";
243                 flags |= F_DEBUG_LINES;
244                 flags |= F_DEBUG_VARS;
245                 flags |= F_DEBUG_SOURCE;
246             } else if (argv[i].equals("-g:none")) {
247                 if (prior_g!=null && !(prior_g.equals("-g:none")))
248                    error("main.conflicting.options", prior_g, "-g:none");
249                 prior_g = "-g:none";
250                 flags &= ~F_DEBUG_LINES;
251                 flags &= ~F_DEBUG_VARS;
252                 flags &= ~F_DEBUG_SOURCE;
253             } else if (argv[i].startsWith("-g:")) {
254                 // We choose to have debugging options conflict even
255                 // if they amount to the same thing (for example,
256                 // -g:source,lines and -g:lines,source).  However, multiple
257                 // debugging options are allowed if they are textually
258                 // identical.
259                 if (prior_g!=null && !(prior_g.equals(argv[i])))
260                    error("main.conflicting.options", prior_g, argv[i]);
261                 prior_g = argv[i];
262                 String args = argv[i].substring("-g:".length());
263                 flags &= ~F_DEBUG_LINES;
264                 flags &= ~F_DEBUG_VARS;
265                 flags &= ~F_DEBUG_SOURCE;
266                 while (true) {
267                     if (args.startsWith("lines")) {
268                         flags |= F_DEBUG_LINES;
269                         args = args.substring("lines".length());
270                     } else if (args.startsWith("vars")) {
271                         flags |= F_DEBUG_VARS;
272                         args = args.substring("vars".length());
273                     } else if (args.startsWith("source")) {
274                         flags |= F_DEBUG_SOURCE;
275                         args = args.substring("source".length());
276                     } else {
277                         error("main.bad.debug.option",argv[i]);
278                         usage_error();
279                         return false;  // Stop processing now
280                     }
281                     if (args.length() == 0) break;
282                     if (args.startsWith(","))
283                         args = args.substring(",".length());
284                 }
285             } else if (argv[i].equals("-O")) {
286                 // -O is accepted for backward compatibility, but
287                 // is no longer effective.  Use the undocumented
288                 // -XO option to get the old behavior.
289                 if (prior_O!=null && !(prior_O.equals("-O")))
290                     error("main.conflicting.options", prior_O, "-O");
291                 prior_O = "-O";
292             } else if (argv[i].equals("-nowarn")) {
293                 flags &= ~F_WARNINGS;
294             } else if (argv[i].equals("-deprecation")) {
295                 flags |= F_DEPRECATION;
296             } else if (argv[i].equals("-verbose")) {
297                 flags |= F_VERBOSE;
298             } else if (argv[i].equals("-nowrite")) {
299                 nowrite = true;
300             } else if (argv[i].equals("-classpath")) {
301                 if ((i + 1) < argv.length) {
302                     if (classPathArg!=null) {
303                        error("main.option.already.seen","-classpath");
304                     }
305                     classPathArg = argv[++i];
306                 } else {
307                     error("main.option.requires.argument","-classpath");
308                     usage_error();
309                     return false;  // Stop processing now
310                 }
311             } else if (argv[i].equals("-sourcepath")) {
312                 if ((i + 1) < argv.length) {
313                     if (sourcePathArg != null) {
314                         error("main.option.already.seen","-sourcepath");
315                     }
316                     sourcePathArg = argv[++i];
317                 } else {
318                     error("main.option.requires.argument","-sourcepath");
319                     usage_error();
320                     return false;  // Stop processing now
321                 }
322             } else if (argv[i].equals("-sysclasspath")) {
323                 if ((i + 1) < argv.length) {
324                     if (sysClassPathArg != null) {
325                         error("main.option.already.seen","-sysclasspath");
326                     }
327                     sysClassPathArg = argv[++i];
328                 } else {
329                     error("main.option.requires.argument","-sysclasspath");
330                     usage_error();
331                     return false;  // Stop processing now
332                 }
333             } else if (argv[i].equals("-bootclasspath")) {
334                 if ((i + 1) < argv.length) {
335                     if (sysClassPathArg != null) {
336                         error("main.option.already.seen","-bootclasspath");
337                     }
338                     sysClassPathArg = argv[++i];
339                 } else {
340                     error("main.option.requires.argument","-bootclasspath");
341                     usage_error();
342                     return false;  // Stop processing now
343                 }
344             } else if (argv[i].equals("-encoding")) {
345                 if ((i + 1) < argv.length) {
346                     if (encoding!=null)
347                        error("main.option.already.seen","-encoding");
348                     encoding = argv[++i];
349                 } else {
350                     error("main.option.requires.argument","-encoding");
351                     usage_error();
352                     return false; // Stop processing now
353                 }
354             } else if (argv[i].equals("-target")) {
355                 if ((i + 1) < argv.length) {
356                     if (targetArg!=null)
357                        error("main.option.already.seen","-target");
358                     targetArg = argv[++i];
359                     int j;
360                     for (j=0; j<releases.length; j++) {
361                         if (releases[j].equals(targetArg)) {
362                             majorVersion = majorVersions[j];
363                             minorVersion = minorVersions[j];
364                             break;
365                         }
366                     }
367                     if (j==releases.length) {
368                         error("main.unknown.release",targetArg);
369                         usage_error();
370                         return false; // Stop processing now
371                     }
372                 } else {
373                     error("main.option.requires.argument","-target");
374                     usage_error();
375                     return false; // Stop processing now
376                 }
377             } else if (argv[i].equals("-d")) {
378                 if ((i + 1) < argv.length) {
379                     if (destDir!=null)
380                        error("main.option.already.seen","-d");
381                     destDir = new File(argv[++i]);
382                     if (!destDir.exists()) {
383                         error("main.no.such.directory",destDir.getPath());
384                         usage_error();
385                         return false; // Stop processing now
386                     }
387                 } else {
388                     error("main.option.requires.argument","-d");
389                     usage_error();
390                     return false; // Stop processing now
391                 }
392 // JCOV
393             } else if (argv[i].equals(optJcov)) {
394                     flags |= F_COVERAGE;
395                     flags &= ~F_OPT;
396                     flags &= ~F_OPT_INTERCLASS;
397             } else if ((argv[i].startsWith(optJcovFile)) &&
398                        (argv[i].length() > optJcovFile.length())) {
399                     covFile = new File(argv[i].substring(optJcovFile.length()));
400                     flags &= ~F_OPT;
401                     flags &= ~F_OPT_INTERCLASS;
402                     flags |= F_COVERAGE;
403                     flags |= F_COVDATA;
404 // end JCOV
405             } else if (argv[i].equals("-XO")) {
406                 // This is what -O used to be.  Now undocumented.
407                 if (prior_O!=null && !(prior_O.equals("-XO")))
408                    error("main.conflicting.options", prior_O, "-XO");
409                 prior_O = "-XO";
410                 flags |= F_OPT;
411             } else if (argv[i].equals("-Xinterclass")) {
412                 if (prior_O!=null && !(prior_O.equals("-Xinterclass")))
413                    error("main.conflicting.options", prior_O, "-Xinterclass");
414                 prior_O = "-Xinterclass";
415                 flags |= F_OPT;
416                 flags |= F_OPT_INTERCLASS;
417                 flags |= F_DEPENDENCIES;
418             } else if (argv[i].equals("-Xdepend")) {
419                 flags |= F_DEPENDENCIES;
420             } else if (argv[i].equals("-Xdebug")) {
421                 flags |= F_DUMP;
422             // Unadvertised option used by JWS.  The non-X version should
423             // be removed, but we'll leave it in until we find out for
424             // sure that no one still depends on that option syntax.
425             } else if (argv[i].equals("-xdepend") || argv[i].equals("-Xjws")) {
426                 flags |= F_PRINT_DEPENDENCIES;
427                 // change the default output in this case:
428                 if (out == System.err) {
429                     out = System.out;
430                 }
431             } else if (argv[i].equals("-Xstrictdefault")) {
432                 // Make strict floating point the default
433                 flags |= F_STRICTDEFAULT;
434             } else if (argv[i].equals("-Xverbosepath")) {
435                 verbosePath = true;
436             } else if (argv[i].equals("-Xstdout")) {
437                 out = System.out;
438             } else if (argv[i].equals("-X")) {
439                 error("main.unsupported.usage");
440                 return false; // Stop processing now
441             } else if (argv[i].equals("-Xversion1.2")) {
442                 // Inform the compiler that it need not target VMs
443                 // earlier than version 1.2.  This option is here
444                 // for testing purposes only.  It is deliberately
445                 // kept orthogonal to the -target option in 1.2.0
446                 // for the sake of stability.  These options will
447                 // be merged in a future release.
448                 flags |= F_VERSION12;
449             } else if (argv[i].endsWith(".java")) {
450                 v.addElement(argv[i]);
451             } else {
452                 error("main.no.such.option",argv[i]);
453                 usage_error();
454                 return false; // Stop processing now
455             }
456         }
457         if (v.size() == 0 || exitStatus == EXIT_CMDERR) {
458             usage_error();
459             return false;
460         }
461 
462         // Create our Environment.
463         BatchEnvironment env = BatchEnvironment.create(out,
464                                                        sourcePathArg,
465                                                        classPathArg,
466                                                        sysClassPathArg);
467         if (verbosePath) {
468             output(getText("main.path.msg",
469                            env.sourcePath.toString(),
470                            env.binaryPath.toString()));
471         }
472 
473         env.flags |= flags;
474         env.majorVersion = majorVersion;
475         env.minorVersion = minorVersion;
476 // JCOV
477         env.covFile = covFile;
478 // end JCOV
479         env.setCharacterEncoding(encoding);
480 
481         // Preload the "out of memory" error string just in case we run
482         // out of memory during the compile.
483         String noMemoryErrorString = getText("main.no.memory");
484         String stackOverflowErrorString = getText("main.stack.overflow");
485 
486         env.error(0, "warn.class.is.deprecated", "sun.tools.javac.Main");
487 
488         try {
489             // Parse all input files
490             for (Enumeration<String> e = v.elements() ; e.hasMoreElements() ;) {
491                 File file = new File(e.nextElement());
492                 try {
493                     env.parseFile(ClassFile.newClassFile(file));
494                 } catch (FileNotFoundException ee) {
495                     env.error(0, "cant.read", file.getPath());
496                     exitStatus = EXIT_CMDERR;
497                 }
498             }
499 
500             // Do a post-read check on all newly-parsed classes,
501             // after they have all been read.
502             for (Enumeration<ClassDeclaration> e = env.getClasses() ; e.hasMoreElements() ; ) {
503                 ClassDeclaration c = e.nextElement();
504                 if (c.getStatus() == CS_PARSED) {
505                     if (c.getClassDefinition().isLocal())
506                         continue;
507                     try {
508                         c.getClassDefinition(env);
509                     } catch (ClassNotFound ee) {
510                     }
511                 }
512             }
513 
514             // compile all classes that need compilation
515             ByteArrayOutputStream buf = new ByteArrayOutputStream(4096);
516             boolean done;
517 
518             do {
519                 done = true;
520                 env.flushErrors();
521                 for (Enumeration<ClassDeclaration> e = env.getClasses() ; e.hasMoreElements() ; ) {
522                     ClassDeclaration c = e.nextElement();
523                     SourceClass src;
524 
525                     switch (c.getStatus()) {
526                       case CS_UNDEFINED:
527                         if (!env.dependencies()) {
528                             break;
529                         }
530                         // fall through
531 
532                       case CS_SOURCE:
533                         if (tracing)
534                             env.dtEvent("Main.compile (SOURCE): loading, " + c);
535                         done = false;
536                         env.loadDefinition(c);
537                         if (c.getStatus() != CS_PARSED) {
538                             if (tracing)
539                                 env.dtEvent("Main.compile (SOURCE): not parsed, " + c);
540                             break;
541                         }
542                         // fall through
543 
544                       case CS_PARSED:
545                         if (c.getClassDefinition().isInsideLocal()) {
546                             // the enclosing block will check this one
547                             if (tracing)
548                                 env.dtEvent("Main.compile (PARSED): skipping local class, " + c);
549                             continue;
550                         }
551                         done = false;
552                         if (tracing) env.dtEvent("Main.compile (PARSED): checking, " + c);
553                         src = (SourceClass)c.getClassDefinition(env);
554                         src.check(env);
555                         c.setDefinition(src, CS_CHECKED);
556                         // fall through
557 
558                       case CS_CHECKED:
559                         src = (SourceClass)c.getClassDefinition(env);
560                         // bail out if there were any errors
561                         if (src.getError()) {
562                             if (tracing)
563                                 env.dtEvent("Main.compile (CHECKED): bailing out on error, " + c);
564                             c.setDefinition(src, CS_COMPILED);
565                             break;
566                         }
567                         done = false;
568                         buf.reset();
569                         if (tracing)
570                             env.dtEvent("Main.compile (CHECKED): compiling, " + c);
571                         src.compile(buf);
572                         c.setDefinition(src, CS_COMPILED);
573                         src.cleanup(env);
574 
575                         if (src.getNestError() || nowrite) {
576                             continue;
577                         }
578 
579                         String pkgName = c.getName().getQualifier().toString().replace('.', File.separatorChar);
580                         String className = c.getName().getFlatName().toString().replace('.', SIGC_INNERCLASS) + ".class";
581 
582                         File file;
583                         if (destDir != null) {
584                             if (pkgName.length() > 0) {
585                                 file = new File(destDir, pkgName);
586                                 if (!file.exists()) {
587                                     file.mkdirs();
588                                 }
589                                 file = new File(file, className);
590                             } else {
591                                 file = new File(destDir, className);
592                             }
593                         } else {
594                             ClassFile classfile = (ClassFile)src.getSource();
595                             if (classfile.isZipped()) {
596                                 env.error(0, "cant.write", classfile.getPath());
597                                 exitStatus = EXIT_CMDERR;
598                                 continue;
599                             }
600                             file = new File(classfile.getPath());
601                             file = new File(file.getParent(), className);
602                         }
603 
604                         // Create the file
605                         try {
606                             FileOutputStream out = new FileOutputStream(file.getPath());
607                             buf.writeTo(out);
608                             out.close();
609 
610                             if (env.verbose()) {
611                                 output(getText("main.wrote", file.getPath()));
612                             }
613                         } catch (IOException ee) {
614                             env.error(0, "cant.write", file.getPath());
615                             exitStatus = EXIT_CMDERR;
616                         }
617 
618                         // Print class dependencies if requested (-xdepend)
619                         if (env.print_dependencies()) {
620                             src.printClassDependencies(env);
621                         }
622                     }
623                 }
624             } while (!done);
625         } catch (OutOfMemoryError ee) {
626             // The compiler has run out of memory.  Use the error string
627             // which we preloaded.
628             env.output(noMemoryErrorString);
629             exitStatus = EXIT_SYSERR;
630             return false;
631         } catch (StackOverflowError ee) {
632             env.output(stackOverflowErrorString);
633             exitStatus = EXIT_SYSERR;
634             return false;
635         } catch (Error ee) {
636             // We allow the compiler to take an exception silently if a program
637             // error has previously been detected.  Presumably, this makes the
638             // compiler more robust in the face of bad error recovery.
639             if (env.nerrors == 0 || env.dump()) {
640                 ee.printStackTrace();
641                 env.error(0, "fatal.error");
642                 exitStatus = EXIT_ABNORMAL;
643             }
644         } catch (Exception ee) {
645             if (env.nerrors == 0 || env.dump()) {
646                 ee.printStackTrace();
647                 env.error(0, "fatal.exception");
648                 exitStatus = EXIT_ABNORMAL;
649             }
650         }
651 
652         int ndepfiles = env.deprecationFiles.size();
653         if (ndepfiles > 0 && env.warnings()) {
654             int ndeps = env.ndeprecations;
655             Object file1 = env.deprecationFiles.elementAt(0);
656             if (env.deprecation()) {
657                 if (ndepfiles > 1) {
658                     env.error(0, "warn.note.deprecations",
659                               ndepfiles, ndeps);
660                 } else {
661                     env.error(0, "warn.note.1deprecation",
662                               file1, ndeps);
663                 }
664             } else {
665                 if (ndepfiles > 1) {
666                     env.error(0, "warn.note.deprecations.silent",
667                               ndepfiles, ndeps);
668                 } else {
669                     env.error(0, "warn.note.1deprecation.silent",
670                               file1, ndeps);
671                 }
672             }
673         }
674 
675         env.flushErrors();
676         env.shutdown();
677 
678         boolean status = true;
679         if (env.nerrors > 0) {
680             String msg = "";
681             if (env.nerrors > 1) {
682                 msg = getText("main.errors", env.nerrors);
683             } else {
684                 msg = getText("main.1error");
685             }
686             if (env.nwarnings > 0) {
687                 if (env.nwarnings > 1) {
688                     msg += ", " + getText("main.warnings", env.nwarnings);
689                 } else {
690                     msg += ", " + getText("main.1warning");
691                 }
692             }
693             output(msg);
694             if (exitStatus == EXIT_OK) {
695                 // Allow EXIT_CMDERR or EXIT_ABNORMAL to take precedence.
696                 exitStatus = EXIT_ERROR;
697             }
698             status = false;
699         } else {
700             if (env.nwarnings > 0) {
701                 if (env.nwarnings > 1) {
702                     output(getText("main.warnings", env.nwarnings));
703                 } else {
704                     output(getText("main.1warning"));
705                 }
706             }
707         }
708 //JCOV
709         if (env.covdata()) {
710             Assembler CovAsm = new Assembler();
711             CovAsm.GenJCov(env);
712         }
713 // end JCOV
714 
715         // We're done
716         if (env.verbose()) {
717             tm = System.currentTimeMillis() - tm;
718             output(getText("main.done_in", Long.toString(tm)));
719         }
720 
721         return status;
722     }
723 
724     /**
725      * Main program
726      */
main(String argv[])727     public static void main(String argv[]) {
728         OutputStream out = System.err;
729 
730         // This is superceeded by the -Xstdout option, but we leave
731         // in the old property check for compatibility.
732         if (Boolean.getBoolean("javac.pipe.output")) {
733             out = System.out;
734         }
735 
736         Main compiler = new Main(out, "javac");
737         System.exit(compiler.compile(argv) ? 0 : compiler.exitStatus);
738     }
739 }
740