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