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 final 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 /** 81 * Can this option be repeated in command line? 82 * 83 * For a repeatable option, multiple values will be merged as comma 84 * separated values rather than the last value overriding previous ones. 85 */ 86 private boolean repeated; 87 88 OptionTemplate(final String resource, final String key, final String value, final boolean isHelp, final boolean isXHelp) { 89 this.resource = resource; 90 this.key = key; 91 this.isHelp = isHelp; 92 this.isXHelp = isXHelp; 93 parse(value); 94 } 95 96 /** 97 * Is this the special help option, used to generate help for 98 * all the others 99 * 100 * @return true if this is the help option 101 */ 102 public boolean isHelp() { 103 return this.isHelp; 104 } 105 106 /** 107 * Is this the special extended help option, used to generate extended help for 108 * all the others 109 * 110 * @return true if this is the extended help option 111 */ 112 public boolean isXHelp() { 113 return this.isXHelp; 114 } 115 116 /** 117 * Get the resource name used to prefix this option set, e.g. "nashorn" 118 * 119 * @return the name of the resource 120 */ 121 public String getResource() { 122 return this.resource; 123 } 124 125 /** 126 * Get the type of this option 127 * 128 * @return the type of the option 129 */ 130 public String getType() { 131 return this.type; 132 } 133 134 /** 135 * Get the key of this option 136 * 137 * @return the key 138 */ 139 public String getKey() { 140 return this.key; 141 } 142 143 /** 144 * Get the default value for this option 145 * 146 * @return the default value as a string 147 */ 148 public String getDefaultValue() { 149 switch (getType()) { 150 case "boolean": 151 if (this.defaultValue == null) { 152 this.defaultValue = "false"; 153 } 154 break; 155 case "integer": 156 if (this.defaultValue == null) { 157 this.defaultValue = "0"; 158 } 159 break; 160 case "timezone": 161 this.defaultValue = TimeZone.getDefault().getID(); 162 break; 163 case "locale": 164 this.defaultValue = Locale.getDefault().toLanguageTag(); 165 break; 166 default: 167 break; 168 } 169 return this.defaultValue; 170 } 171 172 /** 173 * Does this option automatically enable another option, i.e. a dependency. 174 * @return the dependency or null if none exists 175 */ 176 public String getDependency() { 177 return this.dependency; 178 } 179 180 /** 181 * Is this option in conflict with another option so that both can't be enabled 182 * at the same time 183 * 184 * @return the conflicting option or null if none exists 185 */ 186 public String getConflict() { 187 return this.conflict; 188 } 189 190 /** 191 * Is this option undocumented, i.e. should not show up in the standard help output 192 * 193 * @return true if option is undocumented 194 */ 195 public boolean isUndocumented() { 196 return this.isUndocumented; 197 } 198 199 /** 200 * Get the short version of this option name if one exists, e.g. "-co" for "--compile-only" 201 * 202 * @return the short name 203 */ 204 public String getShortName() { 205 return this.shortName; 206 } 207 208 /** 209 * Get the name of this option, e.g. "--compile-only". A name always exists 210 * 211 * @return the name of the option 212 */ 213 public String getName() { 214 return this.name; 215 } 216 217 /** 218 * Get the description of this option. 219 * 220 * @return the description 221 */ 222 public String getDescription() { 223 return this.description; 224 } 225 226 /** 227 * Is value of this option passed as next argument? 228 * @return boolean 229 */ 230 public boolean isValueNextArg() { 231 return valueNextArg; 232 } 233 234 /** 235 * Can this option be repeated? 236 * @return boolean 237 */ 238 public boolean isRepeated() { 239 return repeated; 240 } 241 242 private static String strip(final String value, final char start, final char end) { 243 final int len = value.length(); 244 if (len > 1 && value.charAt(0) == start && value.charAt(len - 1) == end) { 245 return value.substring(1, len - 1); 246 } 247 return null; 248 } 249 250 private void parse(final String origValue) { 251 String value = origValue.trim(); 252 253 try { 254 value = OptionTemplate.strip(value, '{', '}'); 255 final QuotedStringTokenizer keyValuePairs = new QuotedStringTokenizer(value, ","); 256 257 while (keyValuePairs.hasMoreTokens()) { 258 final String keyValue = keyValuePairs.nextToken(); 259 final QuotedStringTokenizer st = new QuotedStringTokenizer(keyValue, "="); 260 final String keyToken = st.nextToken(); 261 final String arg = st.nextToken(); 262 263 switch (keyToken) { 264 case "is_undocumented": 265 this.isUndocumented = Boolean.parseBoolean(arg); 266 break; 267 case "name": 268 if (!arg.startsWith("-")) { 269 throw new IllegalArgumentException(arg); 270 } 271 this.name = arg; 272 break; 273 case "short_name": 274 if (!arg.startsWith("-")) { 275 throw new IllegalArgumentException(arg); 276 } 277 this.shortName = arg; 278 break; 279 case "desc": 280 this.description = arg; 281 break; 282 case "params": 283 this.params = arg; 284 break; 285 case "type": 286 this.type = arg.toLowerCase(Locale.ENGLISH); 287 break; 288 case "default": 289 this.defaultValue = arg; 290 break; 291 case "dependency": 292 this.dependency = arg; 293 break; 294 case "conflict": 295 this.conflict = arg; 296 break; 297 case "value_next_arg": 298 this.valueNextArg = Boolean.parseBoolean(arg); 299 break; 300 case "repeated": 301 this.repeated = true; 302 break; 303 default: 304 throw new IllegalArgumentException(keyToken); 305 } 306 } 307 308 // default to boolean if no type is given 309 if (this.type == null) { 310 this.type = "boolean"; 311 } 312 313 if (this.params == null && "boolean".equals(this.type)) { 314 this.params = "[true|false]"; 315 } 316 317 } catch (final Exception e) { 318 throw new IllegalArgumentException(origValue); 319 } 320 321 if (name == null && shortName == null) { 322 throw new IllegalArgumentException(origValue); 323 } 324 325 if (this.repeated && !"string".equals(this.type)) { 326 throw new IllegalArgumentException("repeated option should be of type string: " + this.name); 327 } 328 } 329 330 boolean nameMatches(final String aName) { 331 return aName.equals(this.shortName) || aName.equals(this.name); 332 } 333 334 private static final int LINE_BREAK = 64; 335 336 @Override 337 public String toString() { 338 final StringBuilder sb = new StringBuilder(); 339 340 sb.append('\t'); 341 342 if (shortName != null) { 343 sb.append(shortName); 344 if (name != null) { 345 sb.append(", "); 346 } 347 } 348 349 if (name != null) { 350 sb.append(name); 351 } 352 353 if (description != null) { 354 final int indent = sb.length(); 355 sb.append(' '); 356 sb.append('('); 357 int pos = 0; 358 for (final char c : description.toCharArray()) { 359 sb.append(c); 360 pos++; 361 if (pos >= LINE_BREAK && Character.isWhitespace(c)) { 362 pos = 0; 363 sb.append("\n\t"); 364 for (int i = 0; i < indent; i++) { 365 sb.append(' '); 366 } 367 } 368 } 369 sb.append(')'); 370 } 371 372 if (params != null) { 373 sb.append('\n'); 374 sb.append('\t'); 375 sb.append('\t'); 376 sb.append(Options.getMsg("nashorn.options.param")).append(": "); 377 sb.append(params); 378 sb.append(" "); 379 final Object def = this.getDefaultValue(); 380 if (def != null) { 381 sb.append(Options.getMsg("nashorn.options.default")).append(": "); 382 sb.append(this.getDefaultValue()); 383 } 384 } 385 386 387 return sb.toString(); 388 } 389 390 @Override 391 public int compareTo(final OptionTemplate o) { 392 return this.getKey().compareTo(o.getKey()); 393 } 394 }