duke@1: /* ohair@554: * Copyright (c) 2006, 2008, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as ohair@554: * published by the Free Software Foundation. Oracle designates this duke@1: * particular file as subject to the "Classpath" exception as provided ohair@554: * by Oracle in the LICENSE file that accompanied this code. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: package com.sun.tools.javac.main; duke@1: jjg@377: import java.io.PrintWriter; jjg@377: import java.util.LinkedHashMap; jjg@377: import java.util.Map; duke@1: import com.sun.tools.javac.util.Log; duke@1: import com.sun.tools.javac.util.Options; duke@1: duke@1: /** duke@1: * TODO: describe com.sun.tools.javac.main.JavacOption duke@1: * jjg@581: *

This is NOT part of any supported API. duke@1: * If you write code that depends on this, you do so at your own duke@1: * risk. This code and its internal interfaces are subject to change duke@1: * or deletion without notice.

duke@1: */ duke@1: public interface JavacOption { duke@1: duke@1: OptionKind getKind(); duke@1: jjg@11: /** Does this option take a (separate) operand? jjg@11: * @return true if this option takes a separate operand jjg@11: */ duke@1: boolean hasArg(); duke@1: duke@1: /** Does argument string match option pattern? jjg@11: * @param arg the command line argument string jjg@11: * @return true if {@code arg} matches this option duke@1: */ duke@1: boolean matches(String arg); duke@1: jjg@11: /** Process an option with an argument. jjg@11: * @param options the accumulated set of analyzed options jjg@11: * @param option the option to be processed jjg@11: * @param arg the arg for the option to be processed jjg@11: * @return true if an error was detected duke@1: */ duke@1: boolean process(Options options, String option, String arg); duke@1: jjg@11: /** Process the option with no argument. jjg@11: * @param options the accumulated set of analyzed options jjg@11: * @param option the option to be processed jjg@11: * @return true if an error was detected duke@1: */ duke@1: boolean process(Options options, String option); duke@1: duke@1: OptionName getName(); duke@1: duke@1: enum OptionKind { duke@1: NORMAL, duke@1: EXTENDED, duke@1: HIDDEN, duke@1: } duke@1: jjg@11: enum ChoiceKind { jjg@11: ONEOF, jjg@11: ANYOF jjg@11: } jjg@11: duke@1: /** This class represents an option recognized by the main program duke@1: */ duke@1: static class Option implements JavacOption { duke@1: duke@1: /** Option string. duke@1: */ duke@1: OptionName name; duke@1: duke@1: /** Documentation key for arguments. duke@1: */ duke@1: String argsNameKey; duke@1: duke@1: /** Documentation key for description. duke@1: */ duke@1: String descrKey; duke@1: duke@1: /** Suffix option (-foo=bar or -foo:bar) duke@1: */ duke@1: boolean hasSuffix; duke@1: jjg@11: /** The kind of choices for this option, if any. jjg@11: */ jjg@11: ChoiceKind choiceKind; jjg@11: jjg@377: /** The choices for this option, if any, and whether or not the choices jjg@377: * are hidden jjg@11: */ jjg@377: Map choices; jjg@11: duke@1: Option(OptionName name, String argsNameKey, String descrKey) { duke@1: this.name = name; duke@1: this.argsNameKey = argsNameKey; duke@1: this.descrKey = descrKey; duke@1: char lastChar = name.optionName.charAt(name.optionName.length()-1); duke@1: hasSuffix = lastChar == ':' || lastChar == '='; duke@1: } jjg@11: duke@1: Option(OptionName name, String descrKey) { duke@1: this(name, null, descrKey); duke@1: } duke@1: jjg@11: Option(OptionName name, String descrKey, ChoiceKind choiceKind, String... choices) { jjg@377: this(name, descrKey, choiceKind, createChoices(choices)); jjg@11: } jjg@11: jjg@377: private static Map createChoices(String... choices) { jjg@377: Map map = new LinkedHashMap(); jjg@377: for (String c: choices) jjg@438: map.put(c, false); jjg@377: return map; jjg@377: } jjg@377: jjg@377: Option(OptionName name, String descrKey, ChoiceKind choiceKind, jjg@377: Map choices) { jjg@11: this(name, null, descrKey); jjg@11: if (choiceKind == null || choices == null) jjg@11: throw new NullPointerException(); jjg@11: this.choiceKind = choiceKind; jjg@11: this.choices = choices; jjg@11: } jjg@11: jjg@11: @Override duke@1: public String toString() { duke@1: return name.optionName; duke@1: } duke@1: duke@1: public boolean hasArg() { duke@1: return argsNameKey != null && !hasSuffix; duke@1: } duke@1: jjg@11: public boolean matches(String option) { jjg@11: if (!hasSuffix) jjg@11: return option.equals(name.optionName); jjg@11: jjg@11: if (!option.startsWith(name.optionName)) jjg@11: return false; jjg@11: jjg@11: if (choices != null) { jjg@11: String arg = option.substring(name.optionName.length()); jjg@11: if (choiceKind == ChoiceKind.ONEOF) jjg@377: return choices.keySet().contains(arg); jjg@11: else { jjg@11: for (String a: arg.split(",+")) { jjg@377: if (!choices.keySet().contains(a)) jjg@11: return false; jjg@11: } jjg@11: } jjg@11: } jjg@11: jjg@11: return true; duke@1: } duke@1: duke@1: /** Print a line of documentation describing this option, if standard. jjg@11: * @param out the stream to which to write the documentation duke@1: */ duke@1: void help(PrintWriter out) { duke@1: String s = " " + helpSynopsis(); duke@1: out.print(s); jjg@11: for (int j = Math.min(s.length(), 28); j < 29; j++) out.print(" "); duke@1: Log.printLines(out, Main.getLocalizedString(descrKey)); duke@1: } jjg@11: duke@1: String helpSynopsis() { jjg@11: StringBuilder sb = new StringBuilder(); jjg@11: sb.append(name); jjg@11: if (argsNameKey == null) { jjg@11: if (choices != null) { jjg@11: String sep = "{"; jjg@377: for (Map.Entry e: choices.entrySet()) { jjg@377: if (!e.getValue()) { jjg@377: sb.append(sep); jjg@377: sb.append(e.getKey()); jjg@377: sep = ","; jjg@377: } jjg@11: } jjg@11: sb.append("}"); jjg@11: } jjg@11: } else { jjg@11: if (!hasSuffix) jjg@11: sb.append(" "); jjg@11: sb.append(Main.getLocalizedString(argsNameKey)); jjg@11: } jjg@11: jjg@11: return sb.toString(); duke@1: } duke@1: duke@1: /** Print a line of documentation describing this option, if non-standard. jjg@11: * @param out the stream to which to write the documentation duke@1: */ duke@1: void xhelp(PrintWriter out) {} duke@1: duke@1: /** Process the option (with arg). Return true if error detected. duke@1: */ duke@1: public boolean process(Options options, String option, String arg) { jjg@11: if (options != null) { jjg@11: if (choices != null) { jjg@11: if (choiceKind == ChoiceKind.ONEOF) { jjg@11: // some clients like to see just one of option+choice set jjg@377: for (String s: choices.keySet()) jjg@377: options.remove(option + s); jjg@11: String opt = option + arg; jjg@11: options.put(opt, opt); jjg@11: // some clients like to see option (without trailing ":") jjg@11: // set to arg jjg@11: String nm = option.substring(0, option.length() - 1); jjg@11: options.put(nm, arg); jjg@11: } else { jjg@11: // set option+word for each word in arg jjg@11: for (String a: arg.split(",+")) { jjg@11: String opt = option + a; jjg@11: options.put(opt, opt); jjg@11: } jjg@11: } jjg@11: } duke@1: options.put(option, arg); jjg@11: } duke@1: return false; duke@1: } duke@1: duke@1: /** Process the option (without arg). Return true if error detected. duke@1: */ duke@1: public boolean process(Options options, String option) { duke@1: if (hasSuffix) duke@1: return process(options, name.optionName, option.substring(name.optionName.length())); duke@1: else duke@1: return process(options, option, option); duke@1: } duke@1: duke@1: public OptionKind getKind() { return OptionKind.NORMAL; } duke@1: duke@1: public OptionName getName() { return name; } duke@1: }; duke@1: duke@1: /** A nonstandard or extended (-X) option duke@1: */ duke@1: static class XOption extends Option { duke@1: XOption(OptionName name, String argsNameKey, String descrKey) { duke@1: super(name, argsNameKey, descrKey); duke@1: } duke@1: XOption(OptionName name, String descrKey) { duke@1: this(name, null, descrKey); duke@1: } jjg@11: XOption(OptionName name, String descrKey, ChoiceKind kind, String... choices) { jjg@11: super(name, descrKey, kind, choices); jjg@11: } jjg@377: XOption(OptionName name, String descrKey, ChoiceKind kind, Map choices) { jjg@11: super(name, descrKey, kind, choices); jjg@11: } jjg@11: @Override duke@1: void help(PrintWriter out) {} jjg@11: @Override duke@1: void xhelp(PrintWriter out) { super.help(out); } jjg@11: @Override duke@1: public OptionKind getKind() { return OptionKind.EXTENDED; } duke@1: }; duke@1: duke@1: /** A hidden (implementor) option duke@1: */ duke@1: static class HiddenOption extends Option { duke@1: HiddenOption(OptionName name) { duke@1: super(name, null, null); duke@1: } duke@1: HiddenOption(OptionName name, String argsNameKey) { duke@1: super(name, argsNameKey, null); duke@1: } jjg@11: @Override duke@1: void help(PrintWriter out) {} jjg@11: @Override duke@1: void xhelp(PrintWriter out) {} jjg@11: @Override duke@1: public OptionKind getKind() { return OptionKind.HIDDEN; } duke@1: }; duke@1: duke@1: }