blob: 2fae703ab0bdf1c88fc8f1c02e9941bf227a884f [file] [log] [blame]
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.runtime.options;
import java.util.Locale;
import java.util.TimeZone;
import jdk.nashorn.internal.runtime.QuotedStringTokenizer;
/**
* This describes the valid input for an option, as read from the resource
* bundle file. Metainfo such as parameters and description is here as well
* for context sensitive help generation.
*/
public final class OptionTemplate implements Comparable<OptionTemplate> {
/** Resource, e.g. "nashorn" for this option */
private final String resource;
/** Key in the resource bundle */
private final String key;
/** Is this option a help option? */
private final boolean isHelp;
/** Is this option a extended help option? */
private final boolean isXHelp;
/** Name - for example --dump-on-error (usually prefixed with --) */
private String name;
/** Short name - for example -doe (usually prefixed with -) */
private String shortName;
/** Params - a parameter template string */
private String params;
/** Type - e.g. "boolean". */
private String type;
/** Does this option have a default value? */
private String defaultValue;
/** Does this option activate another option when set? */
private String dependency;
/** Does this option conflict with another? */
private String conflict;
/** Is this a documented option that should show up in help? */
private boolean isUndocumented;
/** A longer description of what this option does */
private String description;
/** is the option value specified as next argument? */
private boolean valueNextArg;
OptionTemplate(final String resource, final String key, final String value, final boolean isHelp, final boolean isXHelp) {
this.resource = resource;
this.key = key;
this.isHelp = isHelp;
this.isXHelp = isXHelp;
parse(value);
}
/**
* Is this the special help option, used to generate help for
* all the others
*
* @return true if this is the help option
*/
public boolean isHelp() {
return this.isHelp;
}
/**
* Is this the special extended help option, used to generate extended help for
* all the others
*
* @return true if this is the extended help option
*/
public boolean isXHelp() {
return this.isXHelp;
}
/**
* Get the resource name used to prefix this option set, e.g. "nashorn"
*
* @return the name of the resource
*/
public String getResource() {
return this.resource;
}
/**
* Get the type of this option
*
* @return the type of the option
*/
public String getType() {
return this.type;
}
/**
* Get the key of this option
*
* @return the key
*/
public String getKey() {
return this.key;
}
/**
* Get the default value for this option
*
* @return the default value as a string
*/
public String getDefaultValue() {
switch (getType()) {
case "boolean":
if (this.defaultValue == null) {
this.defaultValue = "false";
}
break;
case "integer":
if (this.defaultValue == null) {
this.defaultValue = "0";
}
break;
case "timezone":
this.defaultValue = TimeZone.getDefault().getID();
break;
case "locale":
this.defaultValue = Locale.getDefault().toLanguageTag();
break;
default:
break;
}
return this.defaultValue;
}
/**
* Does this option automatically enable another option, i.e. a dependency.
* @return the dependency or null if none exists
*/
public String getDependency() {
return this.dependency;
}
/**
* Is this option in conflict with another option so that both can't be enabled
* at the same time
*
* @return the conflicting option or null if none exists
*/
public String getConflict() {
return this.conflict;
}
/**
* Is this option undocumented, i.e. should not show up in the standard help output
*
* @return true if option is undocumented
*/
public boolean isUndocumented() {
return this.isUndocumented;
}
/**
* Get the short version of this option name if one exists, e.g. "-co" for "--compile-only"
*
* @return the short name
*/
public String getShortName() {
return this.shortName;
}
/**
* Get the name of this option, e.g. "--compile-only". A name always exists
*
* @return the name of the option
*/
public String getName() {
return this.name;
}
/**
* Get the description of this option.
*
* @return the description
*/
public String getDescription() {
return this.description;
}
/**
* Is value of this option passed as next argument?
* @return boolean
*/
public boolean isValueNextArg() {
return valueNextArg;
}
private static String strip(final String value, final char start, final char end) {
final int len = value.length();
if (len > 1 && value.charAt(0) == start && value.charAt(len - 1) == end) {
return value.substring(1, len - 1);
}
return null;
}
private void parse(final String origValue) {
String value = origValue.trim();
try {
value = OptionTemplate.strip(value, '{', '}');
final QuotedStringTokenizer keyValuePairs = new QuotedStringTokenizer(value, ",");
while (keyValuePairs.hasMoreTokens()) {
final String keyValue = keyValuePairs.nextToken();
final QuotedStringTokenizer st = new QuotedStringTokenizer(keyValue, "=");
final String keyToken = st.nextToken();
final String arg = st.nextToken();
switch (keyToken) {
case "is_undocumented":
this.isUndocumented = Boolean.parseBoolean(arg);
break;
case "name":
if (!arg.startsWith("-")) {
throw new IllegalArgumentException(arg);
}
this.name = arg;
break;
case "short_name":
if (!arg.startsWith("-")) {
throw new IllegalArgumentException(arg);
}
this.shortName = arg;
break;
case "desc":
this.description = arg;
break;
case "params":
this.params = arg;
break;
case "type":
this.type = arg.toLowerCase(Locale.ENGLISH);
break;
case "default":
this.defaultValue = arg;
break;
case "dependency":
this.dependency = arg;
break;
case "conflict":
this.conflict = arg;
break;
case "value_next_arg":
this.valueNextArg = Boolean.parseBoolean(arg);
break;
default:
throw new IllegalArgumentException(keyToken);
}
}
// default to boolean if no type is given
if (this.type == null) {
this.type = "boolean";
}
if (this.params == null && "boolean".equals(this.type)) {
this.params = "[true|false]";
}
} catch (final Exception e) {
throw new IllegalArgumentException(origValue);
}
if (name == null && shortName == null) {
throw new IllegalArgumentException(origValue);
}
}
boolean nameMatches(final String aName) {
return aName.equals(this.shortName) || aName.equals(this.name);
}
private static final int LINE_BREAK = 64;
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
sb.append('\t');
if (shortName != null) {
sb.append(shortName);
if (name != null) {
sb.append(", ");
}
}
if (name != null) {
sb.append(name);
}
if (description != null) {
final int indent = sb.length();
sb.append(' ');
sb.append('(');
int pos = 0;
for (final char c : description.toCharArray()) {
sb.append(c);
pos++;
if (pos >= LINE_BREAK && Character.isWhitespace(c)) {
pos = 0;
sb.append("\n\t");
for (int i = 0; i < indent; i++) {
sb.append(' ');
}
}
}
sb.append(')');
}
if (params != null) {
sb.append('\n');
sb.append('\t');
sb.append('\t');
sb.append(Options.getMsg("nashorn.options.param")).append(": ");
sb.append(params);
sb.append(" ");
final Object def = this.getDefaultValue();
if (def != null) {
sb.append(Options.getMsg("nashorn.options.default")).append(": ");
sb.append(this.getDefaultValue());
}
}
return sb.toString();
}
@Override
public int compareTo(final OptionTemplate o) {
return this.getKey().compareTo(o.getKey());
}
}