code: /**
   * Copyright (c) 2004-2006, Regents of the University of California
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   *
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   *
   * Neither the name of the University of California, Los Angeles nor the
   * names of its contributors may be used to endorse or promote products
   * derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  package avrora;
  
  import avrora.actions.Action;
  import avrora.core.Program;
  import avrora.core.ProgramReader;
  import cck.help.HelpCategory;
  import cck.text.*;
  import cck.util.*;
  import java.io.*;
  import java.util.*;
  
  /**
   * This is the main entrypoint to Avrora. It is responsible for parsing the options to the main program and
   * selecting the appropriate action. Currently, it also implements the help system.
   *
   * @author Ben L. Titzer
   */
  public class Main {
  
      static final Options mainOptions = new Options();
  
      public static final Option.Str INPUT = mainOptions.newOption("input", "auto",
              "This option selects among the available program formats as input to Avrora. " +
              "For example, the default input format, \"atmel\" selects the assembly " +
              "language format supported by Atmel's assembler.");
      public static final Option.Str ACTION = mainOptions.newOption("action", "simulate",
              "This option selects the action to perform. For example, an action might " +
              "be to load a program into the simulator and run it. For more information, " +
              "see the section on actions.");
      public static final Option.Bool COLORS = mainOptions.newOption("colors", true,
              "This option is used to enable or disable the terminal colors.");
      public static final Option.Bool BANNER = mainOptions.newOption("banner", true,
              "This option is used to enable or disable the printing of the banner.");
      public static final Option.Bool STATUS = mainOptions.newOption("status", true,
              "This option enables and disables printing of status information, for example " +
              "when the simulator is loading a program.");
      public static final Option.Bool STATUS_TIMING = mainOptions.newOption("status-timing", false,
              "This option enables and disables printing of timing with status information, for " +
              "example when the simulator is loading a program.");
      public static final Option.List VERBOSE = mainOptions.newOptionList("verbose", "",
              "This option allows users to enable verbose printing of individual " +
              "subsystems within Avrora. A list can be given with individual items separated " +
              "by commas. For example: -verbose=loader,atmel.flash");
      public static final Option.Bool HELP = mainOptions.newOption("help", false,
              "Displays this help message.");
      public static final Option.Bool LICENSE = mainOptions.newOption("license", false,
              "Display the detailed copyright and license text.");
      public static final Option.Bool HTML = mainOptions.newOption("html", false,
              "For terminal colors. Display terminal colors as HTML tags for " +
              "easier inclusion in webpages.");
      public static final Option.Str CONFIGFILE = mainOptions.newOption("config-file", "",
              "This option can be used to specify a file that contains additional command " +
              "line options to Avrora. Any command-line option can be specified in this " +
              "file. For repeated runs with similar options, the common options can be stored " +
              "in this file for use over multiple runs. Options are processed in the following " +
              "order: " +
              "\n   1) The .avrora file in your home directory " +
              "\n   2) A configuration file specified on the command line " +
              "\n   3) Command line options to Avrora");
  
      /**
       * The <code>main()</code> method is the entrypoint into Avrora. It processes the command line options,
       * looks up the action, and prints help (if there are no arguments or the <code>-help</code> option is
       * specified.
       *
       * @param args an array of strings representing the command line arguments passed by the user
       */
      public static void main(String[] args) {
          try {
              // try to load from ~/.avrora if it exists
              loadUserDefaults();
  
              // parse the command line options
              parseOptions(args);
  
              if ( !CONFIGFILE.isBlank() ) {
                  // if the config-file option is specified, load config file and then re-parse
                  // the arguments specified on the command line
                  loadFile(CONFIGFILE.get());
                  parseOptions(args);
              }
  
              if (args.length == 0 || HELP.get()) {
                  // print the help if there are no arguments or -help is specified
                  printHelp(mainOptions.getArguments());
              } else {
                  // otherwise run the specified action
                  runAction();
              }
  
          } catch (Util.Error e) {
              // report any internal Avrora errors
              e.report();
          } catch (Exception e) {
              // report any other exceptions
              e.printStackTrace();
          }
      }
  
      private static void runAction() throws Exception {
          banner();
  
          Action a = Defaults.getAction(ACTION.get());
          if (a == null) {
              Util.userError("Unknown Action", StringUtil.quote(ACTION.get()));
          } else {
              a.options.process(mainOptions);
              a.run(mainOptions.getArguments());
          }
      }
  
      private static void loadUserDefaults() throws IOException {
          String hdir = System.getProperty("user.home");
          if (hdir == null || "".equals(hdir)) return;
  
          File f = new File(hdir + "/.avrora");
          if (f.exists()) {
              Properties defs = new Properties();
              defs.load(new FileInputStream(f));
              mainOptions.process(defs);
          }
      }
  
      private static void loadFile(String fname) throws IOException {
          checkFileExists(fname);
          File f = new File(fname);
          Properties defs = new Properties();
          defs.load(new FileInputStream(f));
          mainOptions.process(defs);
      }
  
      static HelpCategory buildHelpCategory() {
          HelpCategory hc = new HelpCategory("main", "");
          hc.addSection("OVERVIEW","Avrora is a tool for working with " +
                  "assembly language programs for the AVR architecture microcontrollers " +
                  "and building simulations of hardward devices based on this microcontroller." +
                  "It contains tools to read AVR programs in multiple formats, perform " +
                  "actions on them, and generate output in multiple formats.\n" +
                  "Typical usage is to specify a list of files that contain a program " +
                  "in some format supported by Avrora and then specifying the action " +
                  "to perform on that program. For example, giving the name of a file " +
                  "that contains a program written in assembly language and a simulate " +
                  "action might look like: \n\n" +
                  "avrora -action=simulate -input=atmel program.asm \n\n" +
                  "Other actions that are available include generating a control flow graph of the " +
                  "program or running one of the analysis tools on the program. See the " +
                  "actions section for more information.");
          hc.addOptionSection("The main options to Avrora specify the action to be performed as well as the input " +
                  "format and any general configuration parameters for " +
                  "Avrora. The available main options are listed below along with their types and default " +
                  "values. Each action also has its own set of options. To access help for the options " +
                  "related to an action, specify the name of the action along with the \"help\" option.", mainOptions);
  
          hc.addSubcategorySection("ADDITIONAL HELP CATEGORIES", "Additional help is available on a category by category " +
                  "basis. Below is a list of the additional categories available to provide help with actions, " +
                  "input formats, monitors, and more. To access help for a specific category, specify the " +
                  "\"-help\" option followed by the name of category.", Defaults.getMainCategories());
  
          return hc;
      }
  
      static void printHelp(String[] args) {
          title();
          printUsage();
  
          buildAllCategories();
  
          if (args.length == 0) {
              buildHelpCategory().printHelp();
          } else if (args.length == 1) {
              printHelp(args[0]);
          } else {
              Util.userError("help available for only one category at a time.");
          }
  
          printFooter();
      }
  
      private static void buildAllCategories() {
          HelpCategory hc = new HelpCategory("all", "Print a list of all categories for which help is available.");
          hc.addSection("OVERVIEW", "Avrora provides help in many categories that are all accessible from the command " +
                  "line.");
          hc.addSubcategorySection("ALL HELP CATEGORIES", "Below is a listing of all the help categories available.",
                  Defaults.getAllCategories());
          Defaults.addMainCategory(hc);
      }
  
      private static void printUsage() {
          int[] colors = {Terminal.COLOR_RED,
                          -1,
                          Terminal.COLOR_GREEN,
                          -1,
                          Terminal.COLOR_GREEN,
                          -1,
                          Terminal.COLOR_YELLOW,
                          -1,
                          Terminal.COLOR_YELLOW,
                          -1,
                          Terminal.COLOR_YELLOW,
                          -1};
  
          String[] strs = {"Usage", ": ", "avrora", " [", "-action", "=", "action", "] [", "options", "] ", "<files>"};
          Terminal.print(colors, strs);
          Terminal.nextln();
  
          int[] colors2 = {Terminal.COLOR_RED,
                           -1,
                           Terminal.COLOR_GREEN,
                           -1,
                           Terminal.COLOR_YELLOW,
                           -1};
  
          String[] strs2 = {"Usage", ": ", "avrora -help", " [", "category", "]"};
          Terminal.print(colors2, strs2);
          Terminal.println("\n");
      }
  
      private static void printFooter() {
          Terminal.println("For more information, see the online documentation at ");
          Terminal.printCyan("http://compilers.cs.ucla.edu/avrora");
          Terminal.nextln();
          Terminal.println("To report bugs or seek help, consult the Avrora mailing list: ");
          Terminal.printCyan("http://lists.ucla.edu/cgi-bin/mailman/listinfo/avrora");
          Terminal.nextln();
          Terminal.print("Please include the version number [");
          Terminal.printBrightBlue(Version.TAG.toString());
          Terminal.print("] when posting to the list.");
          Terminal.nextln();
      }
  
      private static void printHelp(String a) {
          HelpCategory hc = Defaults.getHelpCategory(a);
          hc.printHelp();
      }
  
      static void banner() {
          if (!BANNER.get() ) return;
  
          title();
  
          if (LICENSE.get()) {
              String notice =
                      "Copyright (c) 2003-2007, Regents of the University of California \n" +
                      "All rights reserved.\n\n" +
  
                      "Redistribution and use in source and binary forms, with or without " +
                      "modification, are permitted provided that the following conditions " +
                      "are met:\n\n" +
  
                      "Redistributions of source code must retain the above copyright notice, " +
                      "this list of conditions and the following disclaimer.\n\n" +
  
                      "Redistributions in binary form must reproduce the above copyright " +
                      "notice, this list of conditions and the following disclaimer in the " +
                      "documentation and/or other materials provided with the distribution.\n\n" +
  
                      "Neither the name of the University of California, Los Angeles nor the " +
                      "names of its contributors may be used to endorse or promote products " +
                      "derived from this software without specific prior written permission.\n\n" +
  
                      "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS " +
                      "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT " +
                      "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR " +
                      "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT " +
                      "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, " +
                      "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT " +
                      "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, " +
                      "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY " +
                      "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT " +
                      "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE " +
                      "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n";
              Terminal.print(StringUtil.formatParagraphs(notice, 0, 0, Terminal.MAXLINE));
          }
  
      }
  
      static void title() {
          Terminal.printBrightBlue("Avrora ");
          Terminal.print("[");
          Terminal.printBrightBlue(Version.TAG.toString());
          Terminal.print("]");
          Terminal.print(" - (c) 2003-2007 UCLA Compilers Group\n\n");
      }
  
      /**
       * The <code>parseOptions()</code> method takes an array of strings and parses it, extracting the options
       * and storing the option values in the internal state of main.
       *
       * @param args the array of strings to parse into options
       */
      public static void parseOptions(String[] args) {
          mainOptions.parseCommandLine(args);
          Terminal.useColors = COLORS.get();
          Terminal.htmlColors = HTML.get();
          Status.ENABLED = STATUS.get();
          Status.TIMING = STATUS_TIMING.get();
          for ( String str : VERBOSE.get() ) {
              Verbose.setVerbose(str, true);
          }
      }
  
      /**
       * The <code>readProgram()</code> method reads a program from the command line arguments given the format
       * specified at the command line. It will also process the indirect-call edge information and add it to
       * the <code>Program</code> instance returned. This method is primarily used by actions that manipulate
       * programs.
       *
       * @param args an array of strings representing command line arguments with the options removed
       * @return an instance of the <code>Program</code> class if the program can be loaded correctly
       * @throws Exception if there is an error loading the program, such as a file not found exception, parse
       *                   error, etc
       */
      public static Program loadProgram(String[] args) throws Exception {
          Status.begin("Loading " + args[0]);
          ProgramReader reader = Defaults.getProgramReader(INPUT.get());
          reader.options.process(mainOptions);
          Program program = reader.read(args);
          Status.success();
          return program;
      }
  
      public static void checkFilesExist(String[] files) {
          for ( String file : files ) {
              checkFileExists(file);
          }
      }
  
      public static void checkFileExists(String fstr) {
          File f = new File(fstr);
          if ( !f.exists() ) {
              Util.userError("File not found", fstr);
          }
      }
  }
  