1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: GetOpt.java,v 1.2.4.1 2005/08/31 11:46:04 pvedula Exp $
  22  */
  23 
  24 package com.sun.org.apache.xalan.internal.xsltc.cmdline.getopt;
  25 
  26 import java.util.ArrayList;
  27 import java.util.List;
  28 import java.util.ListIterator;
  29 
  30 import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ErrorMsg;
  31 
  32 
  33 /**
  34 * GetOpt is a Java equivalent to the C getopt() library function
  35 * discussed in man page getopt(3C). It provides command line
  36 * parsing for Java applications. It supports the most rules of the
  37 * command line standard (see man page intro(1)) including stacked
  38 * options such as '-sxm' (which is equivalent to -s -x -m); it
  39 * handles special '--' option that signifies the end of options.
  40 * Additionally this implementation of getopt will check for
  41 * mandatory arguments to options such as in the case of
  42 * '-d <file>' it will throw a MissingOptArgException if the
  43 * option argument '<file>' is not included on the commandline.
  44 * getopt(3C) does not check for this.
  45  * @author G Todd Miller
  46 */
  47 public class GetOpt{
  48     public GetOpt(String[] args, String optString){
  49         theOptions = new ArrayList();
  50         int currOptIndex = 0;
  51         theCmdArgs = new ArrayList();
  52         theOptionMatcher = new OptionMatcher(optString);
  53         // fill in the options list
  54         for(int i=0; i<args.length; i++){
  55             String token = args[i];
  56             int tokenLength = token.length();
  57             if(token.equals("--")){         // end of opts
  58                 currOptIndex = i+1;         // set index of first operand
  59                 break;                      // end of options
  60             }
  61             else if(token.startsWith("-") && tokenLength == 2){
  62                 // simple option token such as '-s' found
  63                 theOptions.add(new Option(token.charAt(1)));
  64             }
  65             else if(token.startsWith("-") && tokenLength > 2){
  66                 // stacked options found, such as '-shm'
  67                 // iterate thru the tokens after the dash and
  68                 // add them to theOptions list
  69                 for(int j=1; j<tokenLength; j++){
  70                     theOptions.add(new Option(token.charAt(j)));
  71                 }
  72             }
  73             else if(!token.startsWith("-")){
  74                 // case 1- there are not options stored yet therefore
  75                 // this must be an command argument, not an option argument
  76                 if(theOptions.size() == 0){
  77                     currOptIndex = i;
  78                     break;              // stop processing options
  79                 }
  80                 else {
  81                     // case 2-
  82                     // there are options stored, check to see if
  83                     // this arg belong to the last arg stored
  84                     int indexoflast=0;
  85                     indexoflast = theOptions.size()-1;
  86                     Option op = (Option)theOptions.get(indexoflast);
  87                     char opLetter = op.getArgLetter();
  88                     if(!op.hasArg() && theOptionMatcher.hasArg(opLetter)){
  89                         op.setArg(token);
  90                     }
  91                     else{
  92                         // case 3 -
  93                         // the last option stored does not take
  94                         // an argument, so again, this argument
  95                         // must be a command argument, not
  96                         // an option argument
  97                         currOptIndex = i;
  98                         break;                  // end of options
  99                     }
 100                 }
 101             }// end option does not start with "-"
 102         } // end for args loop
 103 
 104         //  attach an iterator to list of options
 105         theOptionsIterator = theOptions.listIterator();
 106 
 107         // options are done, now fill out cmd arg list with remaining args
 108         for(int i=currOptIndex; i<args.length; i++){
 109             String token = args[i];
 110             theCmdArgs.add(token);
 111         }
 112     }
 113 
 114 
 115     /**
 116     * debugging routine to print out all options collected
 117     */
 118     public void printOptions(){
 119         for(ListIterator it=theOptions.listIterator(); it.hasNext();){
 120             Option opt = (Option)it.next();
 121             System.out.print("OPT =" + opt.getArgLetter());
 122             String arg = opt.getArgument();
 123             if(arg != null){
 124                System.out.print(" " + arg);
 125             }
 126             System.out.println();
 127         }
 128     }
 129 
 130     /**
 131     * gets the next option found in the commandline. Distinguishes
 132     * between two bad cases, one case is when an illegal option
 133     * is found, and then other case is when an option takes an
 134     * argument but no argument was found for that option.
 135     * If the option found was not declared in the optString, then
 136     * an IllegalArgumentException will be thrown (case 1).
 137     * If the next option found has been declared to take an argument,
 138     * and no such argument exists, then a MissingOptArgException
 139     * is thrown (case 2).
 140     * @param none
 141     * @return int - the next option found.
 142     * @throws IllegalArgumentException, MissingOptArgException.
 143     */
 144     public int getNextOption() throws IllegalArgumentException,
 145         MissingOptArgException
 146     {
 147         int retval = -1;
 148         if(theOptionsIterator.hasNext()){
 149             theCurrentOption = (Option)theOptionsIterator.next();
 150             char c = theCurrentOption.getArgLetter();
 151             boolean shouldHaveArg = theOptionMatcher.hasArg(c);
 152             String arg = theCurrentOption.getArgument();
 153             if(!theOptionMatcher.match(c)) {
 154                 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CMDLINE_OPTION_ERR,
 155                                             new Character(c));
 156                 throw (new IllegalArgumentException(msg.toString()));
 157             }
 158             else if(shouldHaveArg && (arg == null)) {
 159                 ErrorMsg msg = new ErrorMsg(ErrorMsg.CMDLINE_OPT_MISSING_ARG_ERR,
 160                                             new Character(c));
 161                 throw (new MissingOptArgException(msg.toString()));
 162             }
 163             retval = c;
 164         }
 165         return retval;
 166     }
 167 
 168     /**
 169     * gets the argument for the current parsed option. For example,
 170     * in case of '-d <file>', if current option parsed is 'd' then
 171     * getOptionArg() would return '<file>'.
 172     * @return String - argument for current parsed option.
 173     * @param none
 174     */
 175     public String getOptionArg(){
 176         String retval = null;
 177         String tmp = theCurrentOption.getArgument();
 178         char c = theCurrentOption.getArgLetter();
 179         if(theOptionMatcher.hasArg(c)){
 180             retval = tmp;
 181         }
 182         return retval;
 183     }
 184 
 185     /**
 186     * gets list of the commandline arguments. For example, in command
 187     * such as 'cmd -s -d file file2 file3 file4'  with the usage
 188     * 'cmd [-s] [-d <file>] <file>...', getCmdArgs() would return
 189     * the list {file2, file3, file4}.
 190     * @return String[] - list of command arguments that may appear
 191     *                    after options and option arguments.
 192     * @params none
 193     */
 194     public String[] getCmdArgs(){
 195         String[] retval = new String[theCmdArgs.size()];
 196         int i=0;
 197         for(ListIterator it=theCmdArgs.listIterator(); it.hasNext();){
 198             retval[i++] = (String)it.next();
 199         }
 200         return retval;
 201     }
 202 
 203 
 204     private Option theCurrentOption = null;
 205     private ListIterator theOptionsIterator;
 206     private List theOptions = null;
 207     private List theCmdArgs = null;
 208     private OptionMatcher theOptionMatcher = null;
 209 
 210     ///////////////////////////////////////////////////////////
 211     //
 212     //   Inner Classes
 213     //
 214     ///////////////////////////////////////////////////////////
 215 
 216     // inner class to model an option
 217     class Option{
 218         private char theArgLetter;
 219         private String theArgument = null;
 220         public Option(char argLetter) { theArgLetter = argLetter; }
 221         public void setArg(String arg) {
 222             theArgument = arg;
 223         }
 224         public boolean hasArg() { return (theArgument != null); }
 225         public char getArgLetter() { return theArgLetter; }
 226         public String getArgument() { return theArgument; }
 227     } // end class Option
 228 
 229 
 230     // inner class to query optString for a possible option match,
 231     // and whether or not a given legal option takes an argument.
 232     //
 233     class OptionMatcher{
 234         public OptionMatcher(String optString){
 235             theOptString = optString;
 236         }
 237         public boolean match(char c){
 238             boolean retval = false;
 239             if(theOptString.indexOf(c) != -1){
 240                 retval = true;
 241             }
 242             return retval;
 243         }
 244         public boolean hasArg(char c){
 245             boolean retval = false;
 246             int index = theOptString.indexOf(c)+1;
 247             if (index == theOptString.length()){
 248                 // reached end of theOptString
 249                 retval = false;
 250             }
 251             else if(theOptString.charAt(index) == ':'){
 252                 retval = true;
 253             }
 254             return retval;
 255         }
 256         private String theOptString = null;
 257     } // end class OptionMatcher
 258 }// end class GetOpt