Tue, 08 Nov 2011 17:06:58 -0800
7108669: cleanup Log methods for direct printing to streams
Reviewed-by: mcimadamore
1 /*
2 * Copyright (c) 2006, 2011, 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 */
26 package com.sun.tools.javac.main;
28 import java.util.LinkedHashMap;
29 import java.util.Map;
30 import com.sun.tools.javac.util.Log;
31 import com.sun.tools.javac.util.Log.PrefixKind;
32 import com.sun.tools.javac.util.Log.WriterKind;
33 import com.sun.tools.javac.util.Options;
35 /**
36 * TODO: describe com.sun.tools.javac.main.JavacOption
37 *
38 * <p><b>This is NOT part of any supported API.
39 * If you write code that depends on this, you do so at your own
40 * risk. This code and its internal interfaces are subject to change
41 * or deletion without notice.</b></p>
42 */
43 public interface JavacOption {
45 OptionKind getKind();
47 /** Does this option take a (separate) operand?
48 * @return true if this option takes a separate operand
49 */
50 boolean hasArg();
52 /** Does argument string match option pattern?
53 * @param arg the command line argument string
54 * @return true if {@code arg} matches this option
55 */
56 boolean matches(String arg);
58 /** Process an option with an argument.
59 * @param options the accumulated set of analyzed options
60 * @param option the option to be processed
61 * @param arg the arg for the option to be processed
62 * @return true if an error was detected
63 */
64 boolean process(Options options, String option, String arg);
66 /** Process the option with no argument.
67 * @param options the accumulated set of analyzed options
68 * @param option the option to be processed
69 * @return true if an error was detected
70 */
71 boolean process(Options options, String option);
73 OptionName getName();
75 enum OptionKind {
76 NORMAL,
77 EXTENDED,
78 HIDDEN,
79 }
81 enum ChoiceKind {
82 ONEOF,
83 ANYOF
84 }
86 /** This class represents an option recognized by the main program
87 */
88 static class Option implements JavacOption {
90 /** Option string.
91 */
92 OptionName name;
94 /** Documentation key for arguments.
95 */
96 String argsNameKey;
98 /** Documentation key for description.
99 */
100 String descrKey;
102 /** Suffix option (-foo=bar or -foo:bar)
103 */
104 boolean hasSuffix;
106 /** The kind of choices for this option, if any.
107 */
108 ChoiceKind choiceKind;
110 /** The choices for this option, if any, and whether or not the choices
111 * are hidden
112 */
113 Map<String,Boolean> choices;
115 Option(OptionName name, String argsNameKey, String descrKey) {
116 this.name = name;
117 this.argsNameKey = argsNameKey;
118 this.descrKey = descrKey;
119 char lastChar = name.optionName.charAt(name.optionName.length()-1);
120 hasSuffix = lastChar == ':' || lastChar == '=';
121 }
123 Option(OptionName name, String descrKey) {
124 this(name, null, descrKey);
125 }
127 Option(OptionName name, String descrKey, ChoiceKind choiceKind, String... choices) {
128 this(name, descrKey, choiceKind, createChoices(choices));
129 }
131 private static Map<String,Boolean> createChoices(String... choices) {
132 Map<String,Boolean> map = new LinkedHashMap<String,Boolean>();
133 for (String c: choices)
134 map.put(c, false);
135 return map;
136 }
138 Option(OptionName name, String descrKey, ChoiceKind choiceKind,
139 Map<String,Boolean> choices) {
140 this(name, null, descrKey);
141 if (choiceKind == null || choices == null)
142 throw new NullPointerException();
143 this.choiceKind = choiceKind;
144 this.choices = choices;
145 }
147 @Override
148 public String toString() {
149 return name.optionName;
150 }
152 public boolean hasArg() {
153 return argsNameKey != null && !hasSuffix;
154 }
156 public boolean matches(String option) {
157 if (!hasSuffix)
158 return option.equals(name.optionName);
160 if (!option.startsWith(name.optionName))
161 return false;
163 if (choices != null) {
164 String arg = option.substring(name.optionName.length());
165 if (choiceKind == ChoiceKind.ONEOF)
166 return choices.keySet().contains(arg);
167 else {
168 for (String a: arg.split(",+")) {
169 if (!choices.keySet().contains(a))
170 return false;
171 }
172 }
173 }
175 return true;
176 }
178 /** Print a line of documentation describing this option, if standard.
179 * @param out the stream to which to write the documentation
180 */
181 void help(Log log) {
182 log.printRawLines(WriterKind.NOTICE,
183 String.format(" %-26s %s",
184 helpSynopsis(log),
185 log.localize(PrefixKind.JAVAC, descrKey)));
186 }
188 String helpSynopsis(Log log) {
189 StringBuilder sb = new StringBuilder();
190 sb.append(name);
191 if (argsNameKey == null) {
192 if (choices != null) {
193 String sep = "{";
194 for (Map.Entry<String,Boolean> e: choices.entrySet()) {
195 if (!e.getValue()) {
196 sb.append(sep);
197 sb.append(e.getKey());
198 sep = ",";
199 }
200 }
201 sb.append("}");
202 }
203 } else {
204 if (!hasSuffix)
205 sb.append(" ");
206 sb.append(log.localize(PrefixKind.JAVAC, argsNameKey));
207 }
209 return sb.toString();
210 }
212 /** Print a line of documentation describing this option, if non-standard.
213 * @param out the stream to which to write the documentation
214 */
215 void xhelp(Log log) {}
217 /** Process the option (with arg). Return true if error detected.
218 */
219 public boolean process(Options options, String option, String arg) {
220 if (options != null) {
221 if (choices != null) {
222 if (choiceKind == ChoiceKind.ONEOF) {
223 // some clients like to see just one of option+choice set
224 for (String s: choices.keySet())
225 options.remove(option + s);
226 String opt = option + arg;
227 options.put(opt, opt);
228 // some clients like to see option (without trailing ":")
229 // set to arg
230 String nm = option.substring(0, option.length() - 1);
231 options.put(nm, arg);
232 } else {
233 // set option+word for each word in arg
234 for (String a: arg.split(",+")) {
235 String opt = option + a;
236 options.put(opt, opt);
237 }
238 }
239 }
240 options.put(option, arg);
241 }
242 return false;
243 }
245 /** Process the option (without arg). Return true if error detected.
246 */
247 public boolean process(Options options, String option) {
248 if (hasSuffix)
249 return process(options, name.optionName, option.substring(name.optionName.length()));
250 else
251 return process(options, option, option);
252 }
254 public OptionKind getKind() { return OptionKind.NORMAL; }
256 public OptionName getName() { return name; }
257 };
259 /** A nonstandard or extended (-X) option
260 */
261 static class XOption extends Option {
262 XOption(OptionName name, String argsNameKey, String descrKey) {
263 super(name, argsNameKey, descrKey);
264 }
265 XOption(OptionName name, String descrKey) {
266 this(name, null, descrKey);
267 }
268 XOption(OptionName name, String descrKey, ChoiceKind kind, String... choices) {
269 super(name, descrKey, kind, choices);
270 }
271 XOption(OptionName name, String descrKey, ChoiceKind kind, Map<String,Boolean> choices) {
272 super(name, descrKey, kind, choices);
273 }
274 @Override
275 void help(Log log) {}
276 @Override
277 void xhelp(Log log) { super.help(log); }
278 @Override
279 public OptionKind getKind() { return OptionKind.EXTENDED; }
280 };
282 /** A hidden (implementor) option
283 */
284 static class HiddenOption extends Option {
285 HiddenOption(OptionName name) {
286 super(name, null, null);
287 }
288 HiddenOption(OptionName name, String argsNameKey) {
289 super(name, argsNameKey, null);
290 }
291 @Override
292 void help(Log log) {}
293 @Override
294 void xhelp(Log log) {}
295 @Override
296 public OptionKind getKind() { return OptionKind.HIDDEN; }
297 };
299 }