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      */
  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 
  85     public int getExitStatus() {
  86         return exitStatus;
  87     }
  88 
  89     public boolean compilationPerformedSuccessfully() {
  90         return exitStatus == EXIT_OK || exitStatus == EXIT_ERROR;
  91     }
  92 
  93     public boolean compilationReportedErrors () {
  94         return exitStatus != EXIT_OK;
  95     }
  96 
  97     /**
  98      * Output a message.
  99      */
 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      */
 111     private void error(String msg) {
 112         exitStatus = EXIT_CMDERR;
 113         output(getText(msg));
 114     }
 115 
 116     private void error(String msg, String arg1) {
 117         exitStatus = EXIT_CMDERR;
 118         output(getText(msg, arg1));
 119     }
 120 
 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      */
 131     public void usage_error() {
 132         error("main.usage", program);
 133     }
 134 
 135     private static ResourceBundle messageRB;
 136 
 137     /**
 138      * Initialize ResourceBundle
 139      */
 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      */
 152     public static String getText(String key) {
 153         return getText(key, (String)null);
 154     }
 155 
 156     public static String getText(String key, int num) {
 157         return getText(key, Integer.toString(num));
 158     }
 159 
 160     public static String getText(String key, String fixed) {
 161         return getText(key, fixed, null);
 162     }
 163 
 164     public static String getText(String key, String fixed1, String fixed2) {
 165         return getText(key, fixed1, fixed2, null);
 166     }
 167 
 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")
 196     public synchronized boolean compile(String argv[]) {
 197         String sourcePathArg = null;
 198         String classPathArg = null;
 199         String sysClassPathArg = null;
 200         String extDirsArg = null;
 201         boolean verbosePath = false;
 202 
 203         String targetArg = null;
 204         short majorVersion = JAVA_DEFAULT_VERSION;
 205         short minorVersion = JAVA_DEFAULT_MINOR_VERSION;
 206 
 207         File destDir = null;
 208 //JCOV
 209         File covFile = null;
 210         String optJcov = "-Xjcov";
 211         String optJcovFile = "-Xjcov:file=";
 212 //end JCOV
 213         int flags = F_WARNINGS | F_DEBUG_LINES | F_DEBUG_SOURCE;
 214         long tm = System.currentTimeMillis();
 215         Vector<String> v = new Vector<>();
 216         boolean nowrite = false;
 217         String props = null;
 218         String encoding = null;
 219 
 220         // These flags are used to make sure conflicting -O and -g
 221         // options aren't given.
 222         String prior_g = null;
 223         String prior_O = null;
 224 
 225         exitStatus = EXIT_OK;
 226 
 227         // Pre-process command line for @file arguments
 228         try {
 229             argv = CommandLine.parse(argv);
 230         } catch (FileNotFoundException e) {
 231             error("javac.err.cant.read", e.getMessage());
 232             System.exit(1);
 233         } catch (IOException e) {
 234             e.printStackTrace();
 235             System.exit(1);
 236         }
 237 
 238         // Parse arguments
 239         for (int i = 0 ; i < argv.length ; i++) {
 240             if (argv[i].equals("-g")) {
 241                 if (prior_g!=null && !(prior_g.equals("-g")))
 242                    error("main.conflicting.options", prior_g, "-g");
 243                 prior_g = "-g";
 244                 flags |= F_DEBUG_LINES;
 245                 flags |= F_DEBUG_VARS;
 246                 flags |= F_DEBUG_SOURCE;
 247             } else if (argv[i].equals("-g:none")) {
 248                 if (prior_g!=null && !(prior_g.equals("-g:none")))
 249                    error("main.conflicting.options", prior_g, "-g:none");
 250                 prior_g = "-g:none";
 251                 flags &= ~F_DEBUG_LINES;
 252                 flags &= ~F_DEBUG_VARS;
 253                 flags &= ~F_DEBUG_SOURCE;
 254             } else if (argv[i].startsWith("-g:")) {
 255                 // We choose to have debugging options conflict even
 256                 // if they amount to the same thing (for example,
 257                 // -g:source,lines and -g:lines,source).  However, multiple
 258                 // debugging options are allowed if they are textually
 259                 // identical.
 260                 if (prior_g!=null && !(prior_g.equals(argv[i])))
 261                    error("main.conflicting.options", prior_g, argv[i]);
 262                 prior_g = argv[i];
 263                 String args = argv[i].substring("-g:".length());
 264                 flags &= ~F_DEBUG_LINES;
 265                 flags &= ~F_DEBUG_VARS;
 266                 flags &= ~F_DEBUG_SOURCE;
 267                 while (true) {
 268                     if (args.startsWith("lines")) {
 269                         flags |= F_DEBUG_LINES;
 270                         args = args.substring("lines".length());
 271                     } else if (args.startsWith("vars")) {
 272                         flags |= F_DEBUG_VARS;
 273                         args = args.substring("vars".length());
 274                     } else if (args.startsWith("source")) {
 275                         flags |= F_DEBUG_SOURCE;
 276                         args = args.substring("source".length());
 277                     } else {
 278                         error("main.bad.debug.option",argv[i]);
 279                         usage_error();
 280                         return false;  // Stop processing now
 281                     }
 282                     if (args.length() == 0) break;
 283                     if (args.startsWith(","))
 284                         args = args.substring(",".length());
 285                 }
 286             } else if (argv[i].equals("-O")) {
 287                 // -O is accepted for backward compatibility, but
 288                 // is no longer effective.  Use the undocumented
 289                 // -XO option to get the old behavior.
 290                 if (prior_O!=null && !(prior_O.equals("-O")))
 291                     error("main.conflicting.options", prior_O, "-O");
 292                 prior_O = "-O";
 293             } else if (argv[i].equals("-nowarn")) {
 294                 flags &= ~F_WARNINGS;
 295             } else if (argv[i].equals("-deprecation")) {
 296                 flags |= F_DEPRECATION;
 297             } else if (argv[i].equals("-verbose")) {
 298                 flags |= F_VERBOSE;
 299             } else if (argv[i].equals("-nowrite")) {
 300                 nowrite = true;
 301             } else if (argv[i].equals("-classpath")) {
 302                 if ((i + 1) < argv.length) {
 303                     if (classPathArg!=null) {
 304                        error("main.option.already.seen","-classpath");
 305                     }
 306                     classPathArg = argv[++i];
 307                 } else {
 308                     error("main.option.requires.argument","-classpath");
 309                     usage_error();
 310                     return false;  // Stop processing now
 311                 }
 312             } else if (argv[i].equals("-sourcepath")) {
 313                 if ((i + 1) < argv.length) {
 314                     if (sourcePathArg != null) {
 315                         error("main.option.already.seen","-sourcepath");
 316                     }
 317                     sourcePathArg = argv[++i];
 318                 } else {
 319                     error("main.option.requires.argument","-sourcepath");
 320                     usage_error();
 321                     return false;  // Stop processing now
 322                 }
 323             } else if (argv[i].equals("-sysclasspath")) {
 324                 if ((i + 1) < argv.length) {
 325                     if (sysClassPathArg != null) {
 326                         error("main.option.already.seen","-sysclasspath");
 327                     }
 328                     sysClassPathArg = argv[++i];
 329                 } else {
 330                     error("main.option.requires.argument","-sysclasspath");
 331                     usage_error();
 332                     return false;  // Stop processing now
 333                 }
 334             } else if (argv[i].equals("-bootclasspath")) {
 335                 if ((i + 1) < argv.length) {
 336                     if (sysClassPathArg != null) {
 337                         error("main.option.already.seen","-bootclasspath");
 338                     }
 339                     sysClassPathArg = argv[++i];
 340                 } else {
 341                     error("main.option.requires.argument","-bootclasspath");
 342                     usage_error();
 343                     return false;  // Stop processing now
 344                 }
 345             } else if (argv[i].equals("-extdirs")) {
 346                 if ((i + 1) < argv.length) {
 347                     if (extDirsArg != null) {
 348                         error("main.option.already.seen","-extdirs");
 349                     }
 350                     extDirsArg = argv[++i];
 351                 } else {
 352                     error("main.option.requires.argument","-extdirs");
 353                     usage_error();
 354                     return false;  // Stop processing now
 355                 }
 356             } else if (argv[i].equals("-encoding")) {
 357                 if ((i + 1) < argv.length) {
 358                     if (encoding!=null)
 359                        error("main.option.already.seen","-encoding");
 360                     encoding = argv[++i];
 361                 } else {
 362                     error("main.option.requires.argument","-encoding");
 363                     usage_error();
 364                     return false; // Stop processing now
 365                 }
 366             } else if (argv[i].equals("-target")) {
 367                 if ((i + 1) < argv.length) {
 368                     if (targetArg!=null)
 369                        error("main.option.already.seen","-target");
 370                     targetArg = argv[++i];
 371                     int j;
 372                     for (j=0; j<releases.length; j++) {
 373                         if (releases[j].equals(targetArg)) {
 374                             majorVersion = majorVersions[j];
 375                             minorVersion = minorVersions[j];
 376                             break;
 377                         }
 378                     }
 379                     if (j==releases.length) {
 380                         error("main.unknown.release",targetArg);
 381                         usage_error();
 382                         return false; // Stop processing now
 383                     }
 384                 } else {
 385                     error("main.option.requires.argument","-target");
 386                     usage_error();
 387                     return false; // Stop processing now
 388                 }
 389             } else if (argv[i].equals("-d")) {
 390                 if ((i + 1) < argv.length) {
 391                     if (destDir!=null)
 392                        error("main.option.already.seen","-d");
 393                     destDir = new File(argv[++i]);
 394                     if (!destDir.exists()) {
 395                         error("main.no.such.directory",destDir.getPath());
 396                         usage_error();
 397                         return false; // Stop processing now
 398                     }
 399                 } else {
 400                     error("main.option.requires.argument","-d");
 401                     usage_error();
 402                     return false; // Stop processing now
 403                 }
 404 // JCOV
 405             } else if (argv[i].equals(optJcov)) {
 406                     flags |= F_COVERAGE;
 407                     flags &= ~F_OPT;
 408                     flags &= ~F_OPT_INTERCLASS;
 409             } else if ((argv[i].startsWith(optJcovFile)) &&
 410                        (argv[i].length() > optJcovFile.length())) {
 411                     covFile = new File(argv[i].substring(optJcovFile.length()));
 412                     flags &= ~F_OPT;
 413                     flags &= ~F_OPT_INTERCLASS;
 414                     flags |= F_COVERAGE;
 415                     flags |= F_COVDATA;
 416 // end JCOV
 417             } else if (argv[i].equals("-XO")) {
 418                 // This is what -O used to be.  Now undocumented.
 419                 if (prior_O!=null && !(prior_O.equals("-XO")))
 420                    error("main.conflicting.options", prior_O, "-XO");
 421                 prior_O = "-XO";
 422                 flags |= F_OPT;
 423             } else if (argv[i].equals("-Xinterclass")) {
 424                 if (prior_O!=null && !(prior_O.equals("-Xinterclass")))
 425                    error("main.conflicting.options", prior_O, "-Xinterclass");
 426                 prior_O = "-Xinterclass";
 427                 flags |= F_OPT;
 428                 flags |= F_OPT_INTERCLASS;
 429                 flags |= F_DEPENDENCIES;
 430             } else if (argv[i].equals("-Xdepend")) {
 431                 flags |= F_DEPENDENCIES;
 432             } else if (argv[i].equals("-Xdebug")) {
 433                 flags |= F_DUMP;
 434             // Unadvertised option used by JWS.  The non-X version should
 435             // be removed, but we'll leave it in until we find out for
 436             // sure that no one still depends on that option syntax.
 437             } else if (argv[i].equals("-xdepend") || argv[i].equals("-Xjws")) {
 438                 flags |= F_PRINT_DEPENDENCIES;
 439                 // change the default output in this case:
 440                 if (out == System.err) {
 441                     out = System.out;
 442                 }
 443             } else if (argv[i].equals("-Xstrictdefault")) {
 444                 // Make strict floating point the default
 445                 flags |= F_STRICTDEFAULT;
 446             } else if (argv[i].equals("-Xverbosepath")) {
 447                 verbosePath = true;
 448             } else if (argv[i].equals("-Xstdout")) {
 449                 out = System.out;
 450             } else if (argv[i].equals("-X")) {
 451                 error("main.unsupported.usage");
 452                 return false; // Stop processing now
 453             } else if (argv[i].equals("-Xversion1.2")) {
 454                 // Inform the compiler that it need not target VMs
 455                 // earlier than version 1.2.  This option is here
 456                 // for testing purposes only.  It is deliberately
 457                 // kept orthogonal to the -target option in 1.2.0
 458                 // for the sake of stability.  These options will
 459                 // be merged in a future release.
 460                 flags |= F_VERSION12;
 461             } else if (argv[i].endsWith(".java")) {
 462                 v.addElement(argv[i]);
 463             } else {
 464                 error("main.no.such.option",argv[i]);
 465                 usage_error();
 466                 return false; // Stop processing now
 467             }
 468         }
 469         if (v.size() == 0 || exitStatus == EXIT_CMDERR) {
 470             usage_error();
 471             return false;
 472         }
 473 
 474         // Create our Environment.
 475         BatchEnvironment env = BatchEnvironment.create(out,
 476                                                        sourcePathArg,
 477                                                        classPathArg,
 478                                                        sysClassPathArg,
 479                                                        extDirsArg);
 480         if (verbosePath) {
 481             output(getText("main.path.msg",
 482                            env.sourcePath.toString(),
 483                            env.binaryPath.toString()));
 484         }
 485 
 486         env.flags |= flags;
 487         env.majorVersion = majorVersion;
 488         env.minorVersion = minorVersion;
 489 // JCOV
 490         env.covFile = covFile;
 491 // end JCOV
 492         env.setCharacterEncoding(encoding);
 493 
 494         // Preload the "out of memory" error string just in case we run
 495         // out of memory during the compile.
 496         String noMemoryErrorString = getText("main.no.memory");
 497         String stackOverflowErrorString = getText("main.stack.overflow");
 498 
 499         env.error(0, "warn.class.is.deprecated", "sun.tools.javac.Main");
 500 
 501         try {
 502             // Parse all input files
 503             for (Enumeration<String> e = v.elements() ; e.hasMoreElements() ;) {
 504                 File file = new File(e.nextElement());
 505                 try {
 506                     env.parseFile(new ClassFile(file));
 507                 } catch (FileNotFoundException ee) {
 508                     env.error(0, "cant.read", file.getPath());
 509                     exitStatus = EXIT_CMDERR;
 510                 }
 511             }
 512 
 513             // Do a post-read check on all newly-parsed classes,
 514             // after they have all been read.
 515             for (Enumeration<ClassDeclaration> e = env.getClasses() ; e.hasMoreElements() ; ) {
 516                 ClassDeclaration c = e.nextElement();
 517                 if (c.getStatus() == CS_PARSED) {
 518                     if (c.getClassDefinition().isLocal())
 519                         continue;
 520                     try {
 521                         c.getClassDefinition(env);
 522                     } catch (ClassNotFound ee) {
 523                     }
 524                 }
 525             }
 526 
 527             // compile all classes that need compilation
 528             ByteArrayOutputStream buf = new ByteArrayOutputStream(4096);
 529             boolean done;
 530 
 531             do {
 532                 done = true;
 533                 env.flushErrors();
 534                 for (Enumeration<ClassDeclaration> e = env.getClasses() ; e.hasMoreElements() ; ) {
 535                     ClassDeclaration c = e.nextElement();
 536                     SourceClass src;
 537 
 538                     switch (c.getStatus()) {
 539                       case CS_UNDEFINED:
 540                         if (!env.dependencies()) {
 541                             break;
 542                         }
 543                         // fall through
 544 
 545                       case CS_SOURCE:
 546                         if (tracing)
 547                             env.dtEvent("Main.compile (SOURCE): loading, " + c);
 548                         done = false;
 549                         env.loadDefinition(c);
 550                         if (c.getStatus() != CS_PARSED) {
 551                             if (tracing)
 552                                 env.dtEvent("Main.compile (SOURCE): not parsed, " + c);
 553                             break;
 554                         }
 555                         // fall through
 556 
 557                       case CS_PARSED:
 558                         if (c.getClassDefinition().isInsideLocal()) {
 559                             // the enclosing block will check this one
 560                             if (tracing)
 561                                 env.dtEvent("Main.compile (PARSED): skipping local class, " + c);
 562                             continue;
 563                         }
 564                         done = false;
 565                         if (tracing) env.dtEvent("Main.compile (PARSED): checking, " + c);
 566                         src = (SourceClass)c.getClassDefinition(env);
 567                         src.check(env);
 568                         c.setDefinition(src, CS_CHECKED);
 569                         // fall through
 570 
 571                       case CS_CHECKED:
 572                         src = (SourceClass)c.getClassDefinition(env);
 573                         // bail out if there were any errors
 574                         if (src.getError()) {
 575                             if (tracing)
 576                                 env.dtEvent("Main.compile (CHECKED): bailing out on error, " + c);
 577                             c.setDefinition(src, CS_COMPILED);
 578                             break;
 579                         }
 580                         done = false;
 581                         buf.reset();
 582                         if (tracing)
 583                             env.dtEvent("Main.compile (CHECKED): compiling, " + c);
 584                         src.compile(buf);
 585                         c.setDefinition(src, CS_COMPILED);
 586                         src.cleanup(env);
 587 
 588                         if (src.getNestError() || nowrite) {
 589                             continue;
 590                         }
 591 
 592                         String pkgName = c.getName().getQualifier().toString().replace('.', File.separatorChar);
 593                         String className = c.getName().getFlatName().toString().replace('.', SIGC_INNERCLASS) + ".class";
 594 
 595                         File file;
 596                         if (destDir != null) {
 597                             if (pkgName.length() > 0) {
 598                                 file = new File(destDir, pkgName);
 599                                 if (!file.exists()) {
 600                                     file.mkdirs();
 601                                 }
 602                                 file = new File(file, className);
 603                             } else {
 604                                 file = new File(destDir, className);
 605                             }
 606                         } else {
 607                             ClassFile classfile = (ClassFile)src.getSource();
 608                             if (classfile.isZipped()) {
 609                                 env.error(0, "cant.write", classfile.getPath());
 610                                 exitStatus = EXIT_CMDERR;
 611                                 continue;
 612                             }
 613                             file = new File(classfile.getPath());
 614                             file = new File(file.getParent(), className);
 615                         }
 616 
 617                         // Create the file
 618                         try {
 619                             FileOutputStream out = new FileOutputStream(file.getPath());
 620                             buf.writeTo(out);
 621                             out.close();
 622 
 623                             if (env.verbose()) {
 624                                 output(getText("main.wrote", file.getPath()));
 625                             }
 626                         } catch (IOException ee) {
 627                             env.error(0, "cant.write", file.getPath());
 628                             exitStatus = EXIT_CMDERR;
 629                         }
 630 
 631                         // Print class dependencies if requested (-xdepend)
 632                         if (env.print_dependencies()) {
 633                             src.printClassDependencies(env);
 634                         }
 635                     }
 636                 }
 637             } while (!done);
 638         } catch (OutOfMemoryError ee) {
 639             // The compiler has run out of memory.  Use the error string
 640             // which we preloaded.
 641             env.output(noMemoryErrorString);
 642             exitStatus = EXIT_SYSERR;
 643             return false;
 644         } catch (StackOverflowError ee) {
 645             env.output(stackOverflowErrorString);
 646             exitStatus = EXIT_SYSERR;
 647             return false;
 648         } catch (Error ee) {
 649             // We allow the compiler to take an exception silently if a program
 650             // error has previously been detected.  Presumably, this makes the
 651             // compiler more robust in the face of bad error recovery.
 652             if (env.nerrors == 0 || env.dump()) {
 653                 ee.printStackTrace();
 654                 env.error(0, "fatal.error");
 655                 exitStatus = EXIT_ABNORMAL;
 656             }
 657         } catch (Exception ee) {
 658             if (env.nerrors == 0 || env.dump()) {
 659                 ee.printStackTrace();
 660                 env.error(0, "fatal.exception");
 661                 exitStatus = EXIT_ABNORMAL;
 662             }
 663         }
 664 
 665         int ndepfiles = env.deprecationFiles.size();
 666         if (ndepfiles > 0 && env.warnings()) {
 667             int ndeps = env.ndeprecations;
 668             Object file1 = env.deprecationFiles.elementAt(0);
 669             if (env.deprecation()) {
 670                 if (ndepfiles > 1) {
 671                     env.error(0, "warn.note.deprecations",
 672                               ndepfiles, ndeps);
 673                 } else {
 674                     env.error(0, "warn.note.1deprecation",
 675                               file1, ndeps);
 676                 }
 677             } else {
 678                 if (ndepfiles > 1) {
 679                     env.error(0, "warn.note.deprecations.silent",
 680                               ndepfiles, ndeps);
 681                 } else {
 682                     env.error(0, "warn.note.1deprecation.silent",
 683                               file1, ndeps);
 684                 }
 685             }
 686         }
 687 
 688         env.flushErrors();
 689         env.shutdown();
 690 
 691         boolean status = true;
 692         if (env.nerrors > 0) {
 693             String msg = "";
 694             if (env.nerrors > 1) {
 695                 msg = getText("main.errors", env.nerrors);
 696             } else {
 697                 msg = getText("main.1error");
 698             }
 699             if (env.nwarnings > 0) {
 700                 if (env.nwarnings > 1) {
 701                     msg += ", " + getText("main.warnings", env.nwarnings);
 702                 } else {
 703                     msg += ", " + getText("main.1warning");
 704                 }
 705             }
 706             output(msg);
 707             if (exitStatus == EXIT_OK) {
 708                 // Allow EXIT_CMDERR or EXIT_ABNORMAL to take precedence.
 709                 exitStatus = EXIT_ERROR;
 710             }
 711             status = false;
 712         } else {
 713             if (env.nwarnings > 0) {
 714                 if (env.nwarnings > 1) {
 715                     output(getText("main.warnings", env.nwarnings));
 716                 } else {
 717                     output(getText("main.1warning"));
 718                 }
 719             }
 720         }
 721 //JCOV
 722         if (env.covdata()) {
 723             Assembler CovAsm = new Assembler();
 724             CovAsm.GenJCov(env);
 725         }
 726 // end JCOV
 727 
 728         // We're done
 729         if (env.verbose()) {
 730             tm = System.currentTimeMillis() - tm;
 731             output(getText("main.done_in", Long.toString(tm)));
 732         }
 733 
 734         return status;
 735     }
 736 
 737     /**
 738      * Main program
 739      */
 740     public static void main(String argv[]) {
 741         OutputStream out = System.err;
 742 
 743         // This is superceeded by the -Xstdout option, but we leave
 744         // in the old property check for compatibility.
 745         if (Boolean.getBoolean("javac.pipe.output")) {
 746             out = System.out;
 747         }
 748 
 749         Main compiler = new Main(out, "javac");
 750         System.exit(compiler.compile(argv) ? 0 : compiler.exitStatus);
 751     }
 752 }