1 /*
2 * Copyright (c) 2010, 2013, 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 */
25
26 package jdk.nashorn.internal.runtime.options;
27
28 import java.util.Locale;
29 import java.util.TimeZone;
30 import jdk.nashorn.internal.runtime.QuotedStringTokenizer;
31
32 /**
33 * This describes the valid input for an option, as read from the resource
34 * bundle file. Metainfo such as parameters and description is here as well
35 * for context sensitive help generation.
36 */
37 public class OptionTemplate implements Comparable<OptionTemplate> {
38 /** Resource, e.g. "nashorn" for this option */
39 private final String resource;
40
41 /** Key in the resource bundle */
42 private final String key;
43
44 /** Is this option a help option? */
45 private final boolean isHelp;
46
47 /** Is this option a extended help option? */
48 private final boolean isXHelp;
49
50 /** Name - for example --dump-on-error (usually prefixed with --) */
51 private String name;
52
53 /** Short name - for example -doe (usually prefixed with -) */
54 private String shortName;
55
56 /** Params - a parameter template string */
57 private String params;
58
59 /** Type - e.g. "boolean". */
60 private String type;
61
62 /** Does this option have a default value? */
63 private String defaultValue;
64
65 /** Does this option activate another option when set? */
66 private String dependency;
67
68 /** Does this option conflict with another? */
69 private String conflict;
70
71 /** Is this a documented option that should show up in help? */
72 private boolean isUndocumented;
73
74 /** A longer description of what this option does */
75 private String description;
76
77 /** is the option value specified as next argument? */
78 private boolean valueNextArg;
79
80 OptionTemplate(final String resource, final String key, final String value, final boolean isHelp, final boolean isXHelp) {
81 this.resource = resource;
82 this.key = key;
83 this.isHelp = isHelp;
84 this.isXHelp = isXHelp;
85 parse(value);
86 }
87
88 /**
89 * Is this the special help option, used to generate help for
90 * all the others
91 *
92 * @return true if this is the help option
93 */
94 public boolean isHelp() {
95 return this.isHelp;
96 }
97
98 /**
99 * Is this the special extended help option, used to generate extended help for
100 * all the others
101 *
102 * @return true if this is the extended help option
103 */
104 public boolean isXHelp() {
105 return this.isXHelp;
106 }
107
108 /**
109 * Get the resource name used to prefix this option set, e.g. "nashorn"
110 *
111 * @return the name of the resource
112 */
113 public String getResource() {
114 return this.resource;
115 }
116
117 /**
118 * Get the type of this option
119 *
120 * @return the type of the option
121 */
122 public String getType() {
123 return this.type;
124 }
125
126 /**
127 * Get the key of this option
128 *
129 * @return the key
130 */
131 public String getKey() {
132 return this.key;
133 }
134
135 /**
136 * Get the default value for this option
137 *
138 * @return the default value as a string
139 */
140 public String getDefaultValue() {
141 switch (getType()) {
142 case "boolean":
143 if (this.defaultValue == null) {
144 this.defaultValue = "false";
145 }
146 break;
147 case "integer":
148 if (this.defaultValue == null) {
149 this.defaultValue = "0";
150 }
151 break;
152 case "timezone":
153 this.defaultValue = TimeZone.getDefault().getID();
154 break;
155 case "locale":
156 this.defaultValue = Locale.getDefault().toLanguageTag();
157 break;
158 default:
159 break;
160 }
161 return this.defaultValue;
162 }
163
164 /**
165 * Does this option automatically enable another option, i.e. a dependency.
166 * @return the dependecy or null if non exists
167 */
168 public String getDependency() {
169 return this.dependency;
170 }
171
172 /**
173 * Is this option in conflict with another option so that both can't be enabled
174 * at the same time
175 *
176 * @return the conflicting option or null if none exists
177 */
178 public String getConflict() {
179 return this.conflict;
180 }
181
182 /**
183 * Is this option undocumented, i.e. should not show up in the standard help output
184 *
185 * @return true if option is undocumented
186 */
187 public boolean isUndocumented() {
188 return this.isUndocumented;
189 }
190
191 /**
192 * Get the short version of this option name if one exists, e.g. "-co" for "--compile-only"
193 *
194 * @return the short name
195 */
196 public String getShortName() {
197 return this.shortName;
198 }
199
200 /**
201 * Get the name of this option, e.g. "--compile-only". A name always exists
202 *
203 * @return the name of the option
204 */
205 public String getName() {
206 return this.name;
207 }
208
209 /**
210 * Get the description of this option.
211 *
212 * @return the description
213 */
214 public String getDescription() {
215 return this.description;
216 }
217
218 /**
219 * Is value of this option passed as next argument?
220 * @return boolean
221 */
222 public boolean isValueNextArg() {
223 return valueNextArg;
224 }
225
226 private static String strip(final String value, final char start, final char end) {
227 final int len = value.length();
228 if (len > 1 && value.charAt(0) == start && value.charAt(len - 1) == end) {
229 return value.substring(1, len - 1);
230 }
231 return null;
232 }
233
234 private void parse(final String origValue) {
235 String value = origValue.trim();
236
237 try {
238 value = OptionTemplate.strip(value, '{', '}');
239 final QuotedStringTokenizer keyValuePairs = new QuotedStringTokenizer(value, ",");
240
241 while (keyValuePairs.hasMoreTokens()) {
242 final String keyValue = keyValuePairs.nextToken();
243 final QuotedStringTokenizer st = new QuotedStringTokenizer(keyValue, "=");
244 final String keyToken = st.nextToken();
245 final String arg = st.nextToken();
246
247 switch (keyToken) {
248 case "is_undocumented":
249 this.isUndocumented = Boolean.parseBoolean(arg);
250 break;
251 case "name":
252 if (!arg.startsWith("-")) {
253 throw new IllegalArgumentException(arg);
254 }
255 this.name = arg;
256 break;
257 case "short_name":
258 if (!arg.startsWith("-")) {
259 throw new IllegalArgumentException(arg);
260 }
261 this.shortName = arg;
262 break;
263 case "desc":
264 this.description = arg;
265 break;
266 case "params":
267 this.params = arg;
268 break;
269 case "type":
270 this.type = arg.toLowerCase(Locale.ENGLISH);
271 break;
272 case "default":
273 this.defaultValue = arg;
274 break;
275 case "dependency":
276 this.dependency = arg;
277 break;
278 case "conflict":
279 this.conflict = arg;
280 break;
281 case "value_next_arg":
282 this.valueNextArg = Boolean.parseBoolean(arg);
283 break;
284 default:
285 throw new IllegalArgumentException(keyToken);
286 }
287 }
288
289 // default to boolean if no type is given
290 if (this.type == null) {
291 this.type = "boolean";
292 }
293
294 if (this.params == null && "boolean".equals(this.type)) {
295 this.params = "[true|false]";
296 }
297
298 } catch (final Exception e) {
299 throw new IllegalArgumentException(origValue);
300 }
301
302 if (name == null && shortName == null) {
303 throw new IllegalArgumentException(origValue);
304 }
305 }
306
307 boolean matches(final String key0) {
308 return key0.equals(this.shortName) || key0.equals(this.name);
309 }
310
311 private static final int LINE_BREAK = 64;
312
313 @Override
314 public String toString() {
315 final StringBuilder sb = new StringBuilder();
316
317 sb.append('\t');
318
319 if (shortName != null) {
320 sb.append(shortName);
321 if (name != null) {
322 sb.append(", ");
323 }
324 }
325
326 if (name != null) {
327 sb.append(name);
328 }
329
330 if (description != null) {
331 final int indent = sb.length();
332 sb.append(' ');
333 sb.append('(');
334 int pos = 0;
335 for (final char c : description.toCharArray()) {
336 sb.append(c);
337 pos++;
338 if (pos >= LINE_BREAK && Character.isWhitespace(c)) {
339 pos = 0;
340 sb.append("\n\t");
341 for (int i = 0; i < indent; i++) {
342 sb.append(' ');
343 }
344 }
345 }
346 sb.append(')');
347 }
348
349 if (params != null) {
350 sb.append('\n');
351 sb.append('\t');
352 sb.append('\t');
353 sb.append(Options.getMsg("nashorn.options.param")).append(": ");
354 sb.append(params);
355 sb.append(" ");
356 final Object def = this.getDefaultValue();
357 if (def != null) {
358 sb.append(Options.getMsg("nashorn.options.default")).append(": ");
359 sb.append(this.getDefaultValue());
360 }
361 }
362
363
364 return sb.toString();
365 }
366
367 @Override
368 public int compareTo(final OptionTemplate o) {
369 return this.getKey().compareTo(o.getKey());
370 }
371 }
--- EOF ---