1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * ident        "%Z%%M% %I%     %E% SMI"
  24  *
  25  * Copyright 1998-2002 Sun Microsystems, Inc.  All rights reserved.
  26  * Use is subject to license terms.
  27  */
  28 package com.sun.dhcpmgr.cli.common;
  29 
  30 import java.lang.IllegalArgumentException;
  31 import java.text.MessageFormat;
  32 
  33 /**
  34  * This class provides the functionality for parsing command line
  35  * arguments (similar to getsubopt(3C)).
  36  * <br>
  37  * After constructing an instance of it, getNextSubOption() can be used
  38  * to get the next suboption. getSubOptionArg() can be used to get the argument
  39  * for that option. 
  40  *
  41  */
  42 public class GetSubOpt {
  43 
  44     /**
  45      * Delimiter between suboptions.
  46      */
  47     public final static String OPTION_DELIM = ",";
  48 
  49     /**
  50      * Delimiter between suboption and suboption argument.
  51      */
  52     public final static String VALUE_DELIM =  "=";
  53 
  54     /**
  55      * List of suboptions.
  56      */
  57     protected String subOptions;
  58 
  59     /**
  60      * The length of the suboptions.
  61      */
  62     private final int subOptionsLen;
  63 
  64     /**
  65      * Current position with in suboptions.
  66      */
  67     protected int index;
  68 
  69     /**
  70      * Last suboption found.
  71      */
  72     protected String subOption;
  73 
  74     /**
  75      * Last suboption argument found.
  76      */
  77     protected String value;
  78 
  79     /**
  80      * Prepare a GetSubOpt object.
  81      *
  82      * @param subOptions
  83      *   String containing the list of suboptions. This value was most likely
  84      *   returned as an option argument by <i>GetOpt</i>.
  85      */
  86     public GetSubOpt(String subOptions) {
  87         if (subOptions == null) {
  88             this.subOptions = null;
  89         } else {
  90             this.subOptions = subOptions.trim();
  91         }
  92 
  93         index = 0; 
  94         subOptionsLen = subOptions.length();
  95     }
  96 
  97     /**
  98      * Get the next suboption. The suboptions arguement is available from
  99      * calling <i>getSubOptionArg()</i>.
 100      *
 101      * @return
 102      *   The next suboption.
 103      * @exception IllegalArgumentException
 104      *   Thrown when no more suboptions remain.
 105      */
 106     public String getNextSubOption() throws IllegalArgumentException {
 107 
 108         subOption = null;
 109         value = null;
 110 
 111         while (subOption == null || subOption.length() == 0) {
 112 
 113             if (!hasMoreSubOptions()) {
 114                 String format =
 115                         ResourceStrings.getString("getsubopt_end_of_optionarg");
 116                 Object[] args = new Object[0];
 117                 String msg = MessageFormat.format(format, args);
 118                 throw new IllegalArgumentException(msg);
 119             }
 120 
 121             int optionIndex = subOptions.indexOf(OPTION_DELIM, index);
 122             int valueIndex = subOptions.indexOf(VALUE_DELIM, index);
 123 
 124             if (optionIndex == -1 && valueIndex == -1) {
 125                 // Last suboption and no value.
 126                 subOption = subOptions.substring(index);
 127                 index = subOptionsLen;
 128             } else if (valueIndex == -1 ||
 129                             (optionIndex != -1 && optionIndex < valueIndex)) {
 130                 // Suboption has no value.
 131                 subOption = subOptions.substring(index, optionIndex);
 132                 index = optionIndex + OPTION_DELIM.length();
 133             } else {
 134                 // Suboption with value.
 135                 subOption = subOptions.substring(index, valueIndex);
 136                 index = valueIndex + VALUE_DELIM.length();
 137 
 138                 boolean quoted = false;
 139                 int endIndex;
 140 
 141                 if (index < subOptionsLen &&
 142                             (subOptions.charAt(index) == '\"' ||
 143                                 subOptions.charAt(index) == '\'')) {
 144                     // Value is quoted.
 145                     endIndex =
 146                         subOptions.indexOf(subOptions.charAt(index), index + 1);
 147 
 148                     // Missing close quote. 
 149                     if (endIndex == -1) {
 150                         String format =
 151                                 ResourceStrings.getString(
 152                                     "getsubopt_missing_close_quote");
 153                         Object[] args = new Object[1];
 154                         args[0] = subOption;
 155                         String msg = MessageFormat.format(format, args);
 156                         throw new IllegalArgumentException(msg);
 157                     }
 158  
 159                     quoted = true;
 160                     index++;
 161                 } else {
 162                     // Value is not quoted.
 163                     endIndex = subOptions.indexOf(OPTION_DELIM, index);
 164             
 165                     if (endIndex == -1) {
 166                         endIndex = subOptionsLen;
 167                     }
 168                 }
 169 
 170                 value = subOptions.substring(index, endIndex);
 171                 index = endIndex;
 172 
 173                 // Skip closing quote.
 174                 if (quoted) {
 175                     index++;
 176                 }
 177 
 178                 /*
 179                  * Ensure that either the end of the suboptions has been
 180                  * reached or the next suboption is ready for parsing. For
 181                  * example, quoted values must not contain characters between
 182                  * the closing quote and OPTION_DELIM.
 183                  */
 184                 if (optionIndex >= 0) {
 185                     if (index < subOptionsLen &&
 186                                 !subOptions.startsWith(OPTION_DELIM, index)) {
 187                         String format =
 188                                 ResourceStrings.getString(
 189                                     "getsubopt_malformed_value");
 190                         Object[] args = new Object[1];
 191                         args[0] = subOption;
 192                         String msg = MessageFormat.format(format, args);
 193                         throw new IllegalArgumentException(msg);
 194                     }
 195 
 196                     index += OPTION_DELIM.length();
 197                 }
 198             }
 199         }
 200 
 201         return subOption;
 202     }
 203 
 204     /**
 205      * Indicates whether more suboptions exist.
 206      *
 207      * @return
 208      *   True if at least one more suboption exists, otherwise false.
 209      */
 210     public boolean hasMoreSubOptions() throws IllegalArgumentException {
 211         if (subOptions == null) {
 212             return false;
 213         }
 214 
 215         // Skip over leading OPTION_DELIMs.
 216         while (index < subOptionsLen &&
 217                             subOptions.indexOf(OPTION_DELIM, index) == index) {
 218             index += OPTION_DELIM.length();
 219         }
 220 
 221         /*
 222          * Ensure that there really is a suboption present. If a
 223          * VALUE_DELIM has been found the suboption string is missing.
 224          */
 225         if (index < subOptionsLen &&
 226                             subOptions.indexOf(VALUE_DELIM, index) == index) {
 227             String format =
 228                     ResourceStrings.getString(
 229                         "getsubopt_value_without_suboption");
 230             Object[] args = new Object[0];
 231             String msg = MessageFormat.format(format, args);
 232             throw new IllegalArgumentException(msg);
 233         }
 234 
 235         return (index < subOptionsLen);
 236     }
 237 
 238     /**
 239      * Get the current suboptions argument, or null if no argument is present.
 240      *
 241      * @return
 242      *   String containing the current suboptions argument, or null if the
 243      *   no argument is present.
 244      */
 245     public String getSubOptionArg() {
 246         return value;
 247     }
 248 }
 249