void sort(MessageFile mf, boolean includePrecedingNewlines) {
   for (MessageFile.Message m : mf.messages.values()) {
     for (MessageFile.Line l : m.getLines(includePrecedingNewlines)) {
       l.remove();
       mf.lastLine.insertAfter(l);
     }
   }
 }
 void check(MessageFile mf, File notYetFile) {
   Set<String> notYetList = null;
   for (Map.Entry<String, MessageFile.Message> e : mf.messages.entrySet()) {
     String key = e.getKey();
     MessageFile.Message m = e.getValue();
     if (m.needInfo() && m.getInfo().isEmpty()) {
       if (notYetList == null) notYetList = getNotYetList(notYetFile);
       if (notYetList.contains(key)) System.err.println("Warning: no info for " + key);
       else error("no info for " + key);
     }
   }
 }
  boolean run(String... args) {
    File testSrc = new File(System.getProperty("test.src", "."));
    File examplesDir = new File(testSrc, "examples");
    File notYetFile = null;
    File msgFile = null;
    File outFile = null;
    boolean verbose = false;
    boolean ensureNewlines = false;
    boolean fixIndent = false;
    boolean sort = false;
    boolean replace = false;
    boolean check = jtreg; // default true in jtreg mode

    for (int i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.equals("-examples") && (i + 1) < args.length) examplesDir = new File(args[++i]);
      else if (arg.equals("-notyet") && (i + 1) < args.length) notYetFile = new File(args[++i]);
      else if (arg.equals("-ensureNewlines")) ensureNewlines = true;
      else if (arg.equals("-fixIndent")) fixIndent = true;
      else if (arg.equals("-sort")) sort = true;
      else if (arg.equals("-verbose")) verbose = true;
      else if (arg.equals("-replace")) replace = true;
      else if (arg.equals("-check")) check = true;
      else if (arg.equals("-o") && (i + 1) < args.length) outFile = new File(args[++i]);
      else if (arg.startsWith("-")) {
        error("unknown option: " + arg);
        return false;
      } else if (i == args.length - 1) {
        msgFile = new File(arg);
      } else {
        error("unknown arg: " + arg);
        return false;
      }
    }

    if (!check && outFile == null) {
      usage();
      return true;
    }

    if ((ensureNewlines || fixIndent || sort) && outFile == null) {
      error("must set output file for these options");
      return false;
    }

    if (notYetFile == null) {
      notYetFile = new File(examplesDir.getParentFile(), "examples.not-yet.txt");
    }

    if (msgFile == null) {
      for (File d = testSrc; d != null; d = d.getParentFile()) {
        if (new File(d, "TEST.ROOT").exists()) {
          d = d.getParentFile();
          File f =
              new File(d, "src/share/classes/com/sun/tools/javac/resources/compiler.properties");
          if (f.exists()) {
            msgFile = f;
            break;
          }
        }
      }
      if (msgFile == null) {
        if (jtreg) {
          System.err.println("Warning: no message file available, test skipped");
          return true;
        }
        error("no message file available");
        return false;
      }
    }

    MessageFile mf;
    try {
      mf = new MessageFile(msgFile);
    } catch (IOException e) {
      error("problem reading message file: " + e);
      return false;
    }

    Map<String, Set<String>> msgInfo = runExamples(examplesDir, verbose);

    if (ensureNewlines) ensureNewlines(mf);

    if (fixIndent) fixIndent(mf);

    if (sort) sort(mf, true);

    for (Map.Entry<String, Set<String>> e : msgInfo.entrySet()) {
      String k = e.getKey();
      Set<String> suggestions = e.getValue();
      MessageFile.Message m = mf.messages.get(k);
      if (m == null) {
        error("Can't find message for " + k + " in message file");
        continue;
      }

      MessageFile.Info info = m.getInfo();
      Set<Integer> placeholders = m.getPlaceholders();
      MessageFile.Info suggestedInfo = new MessageFile.Info(suggestions);
      suggestedInfo.markUnused(placeholders);

      if (!info.isEmpty()) {
        if (info.contains(suggestedInfo)) continue;
        if (!replace) {
          if (info.fields.size() != suggestedInfo.fields.size())
            error("Cannot merge info for " + k);
          else suggestedInfo.merge(info);
        }
      }

      if (outFile == null) {
        System.err.println("suggest for " + k);
        System.err.println(suggestedInfo.toComment());
      } else m.setInfo(suggestedInfo);
    }

    if (check) check(mf, notYetFile);

    try {
      if (outFile != null) mf.write(outFile);
    } catch (IOException e) {
      error("problem writing file: " + e);
      return false;
    }

    return (errors == 0);
  }