private void extractArguments(String[] args) {
    String testArgsString = Config.getString("AutoGrader.testArgs");
    if (testArgsString == null) {
      testArgsString = "";
    }

    for (int i = 0; i < args.length; ) {
      String arg = args[i++];
      if (arg.length() > 0 && arg.charAt(0) == '-') {
        if (arg.equals("-#")) {
          Lib.assertTrue(i < args.length, "-# switch missing argument");
          testArgsString = args[i++];
        }
      }
    }

    StringTokenizer st = new StringTokenizer(testArgsString, ",\n\t\f\r");

    while (st.hasMoreTokens()) {
      StringTokenizer pair = new StringTokenizer(st.nextToken(), "=");

      Lib.assertTrue(pair.hasMoreTokens(), "test argument missing key");
      String key = pair.nextToken();

      Lib.assertTrue(pair.hasMoreTokens(), "test argument missing value");
      String value = pair.nextToken();

      testArgs.put(key, value);
    }
  }
  /**
   * Nachos main entry point.
   *
   * @param args the command line arguments.
   */
  public static void main(final String[] args) {
    System.out.print("nachos 5.0j initializing...");

    Lib.assertTrue(Machine.args == null);
    Machine.args = args;

    processArgs();

    Config.load(configFileName);

    // get the current directory (.)
    baseDirectory = new File(new File("").getAbsolutePath());
    // get the nachos directory (./nachos)
    nachosDirectory = new File(baseDirectory, "nachos");

    String testDirectoryName = Config.getString("FileSystem.testDirectory");

    // get the test directory
    if (testDirectoryName != null) {
      testDirectory = new File(testDirectoryName);
    } else {
      // use ../test
      testDirectory = new File(baseDirectory.getParentFile(), "test");
    }

    securityManager = new NachosSecurityManager(testDirectory);
    privilege = securityManager.getPrivilege();

    privilege.machine = new MachinePrivilege();

    TCB.givePrivilege(privilege);
    privilege.stats = stats;

    securityManager.enable();
    createDevices();
    checkUserClasses();

    autoGrader = (AutoGrader) Lib.constructObject(autoGraderClassName);

    new TCB()
        .start(
            new Runnable() {
              public void run() {
                autoGrader.start(privilege);
              }
            });
  }
  /**
   * Start this autograder. Extract the <tt>-#</tt> arguments, call <tt>init()</tt>, load and
   * initialize the kernel, and call <tt>run()</tt>.
   *
   * @param privilege encapsulates privileged access to the Nachos machine.
   */
  public void start(Privilege privilege) {
    Lib.assertTrue(this.privilege == null, "start() called multiple times");
    this.privilege = privilege;

    String[] args = Machine.getCommandLineArguments();

    extractArguments(args);

    System.out.print(" grader");

    init();

    System.out.print("\n");

    kernel = (Kernel) Lib.constructObject(Config.getString("Kernel.kernel"));
    kernel.initialize(args);

    run();
  }
  private static void createDevices() {
    interrupt = new Interrupt(privilege);
    timer = new Timer(privilege);

    if (Config.getBoolean("Machine.bank")) bank = new ElevatorBank(privilege);

    if (Config.getBoolean("Machine.processor")) {
      if (numPhysPages == -1) numPhysPages = Config.getInteger("Processor.numPhysPages");
      processor = new Processor(privilege, numPhysPages);
    }

    if (Config.getBoolean("Machine.console")) console = new StandardConsole(privilege);

    if (Config.getBoolean("Machine.stubFileSystem"))
      stubFileSystem = new StubFileSystem(privilege, testDirectory);

    if (Config.getBoolean("Machine.networkLink")) networkLink = new NetworkLink(privilege);
  }
  /**
   * Return the name of the process class that the kernel should use. In the multi-programming
   * project, returns <tt>nachos.userprog.UserProcess</tt>. In the VM project, returns
   * <tt>nachos.vm.VMProcess</tt>. In the networking project, returns
   * <tt>nachos.network.NetProcess</tt>.
   *
   * @return the name of the process class that the kernel should use.
   * @see nachos.userprog.UserKernel#run
   * @see nachos.userprog.UserProcess
   * @see nachos.vm.VMProcess
   * @see nachos.network.NetProcess
   */
  public static String getProcessClassName() {
    if (processClassName == null) processClassName = Config.getString("Kernel.processClassName");

    Lib.assertTrue(processClassName != null);
    return processClassName;
  }
  /**
   * Return the name of the shell program that a user-programming kernel must run. Make sure
   * <tt>UserKernel.run()</tt> <i>always</i> uses this method to decide which program to run.
   *
   * @return the name of the shell program to run.
   */
  public static String getShellProgramName() {
    if (shellProgramName == null) shellProgramName = Config.getString("Kernel.shellProgram");

    Lib.assertTrue(shellProgramName != null);
    return shellProgramName;
  }