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 ---