001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: GetOpt.java 1225436 2011-12-29 05:09:31Z mrglavas $ 020 */ 021 022 package org.apache.xalan.xsltc.cmdline.getopt; 023 024 import java.util.ArrayList; 025 import java.util.List; 026 import java.util.ListIterator; 027 028 import org.apache.xalan.xsltc.compiler.util.ErrorMsg; 029 030 031 /** 032 * GetOpt is a Java equivalent to the C getopt() library function 033 * discussed in man page getopt(3C). It provides command line 034 * parsing for Java applications. It supports the most rules of the 035 * command line standard (see man page intro(1)) including stacked 036 * options such as '-sxm' (which is equivalent to -s -x -m); it 037 * handles special '--' option that signifies the end of options. 038 * Additionally this implementation of getopt will check for 039 * mandatory arguments to options such as in the case of 040 * '-d <file>' it will throw a MissingOptArgException if the 041 * option argument '<file>' is not included on the commandline. 042 * getopt(3C) does not check for this. 043 * @author G Todd Miller 044 */ 045 public class GetOpt{ 046 public GetOpt(String[] args, String optString){ 047 theOptions = new ArrayList(); 048 int currOptIndex = 0; 049 theCmdArgs = new ArrayList(); 050 theOptionMatcher = new OptionMatcher(optString); 051 // fill in the options list 052 for(int i=0; i<args.length; i++){ 053 String token = args[i]; 054 int tokenLength = token.length(); 055 if(token.equals("--")){ // end of opts 056 currOptIndex = i+1; // set index of first operand 057 break; // end of options 058 } 059 else if(token.startsWith("-") && tokenLength == 2){ 060 // simple option token such as '-s' found 061 theOptions.add(new Option(token.charAt(1))); 062 } 063 else if(token.startsWith("-") && tokenLength > 2){ 064 // stacked options found, such as '-shm' 065 // iterate thru the tokens after the dash and 066 // add them to theOptions list 067 for(int j=1; j<tokenLength; j++){ 068 theOptions.add(new Option(token.charAt(j))); 069 } 070 } 071 else if(!token.startsWith("-")){ 072 // case 1- there are not options stored yet therefore 073 // this must be an command argument, not an option argument 074 if(theOptions.size() == 0){ 075 currOptIndex = i; 076 break; // stop processing options 077 } 078 else { 079 // case 2- 080 // there are options stored, check to see if 081 // this arg belong to the last arg stored 082 int indexoflast=0; 083 indexoflast = theOptions.size()-1; 084 Option op = (Option)theOptions.get(indexoflast); 085 char opLetter = op.getArgLetter(); 086 if(!op.hasArg() && theOptionMatcher.hasArg(opLetter)){ 087 op.setArg(token); 088 } 089 else{ 090 // case 3 - 091 // the last option stored does not take 092 // an argument, so again, this argument 093 // must be a command argument, not 094 // an option argument 095 currOptIndex = i; 096 break; // end of options 097 } 098 } 099 }// end option does not start with "-" 100 } // end for args loop 101 102 // attach an iterator to list of options 103 theOptionsIterator = theOptions.listIterator(); 104 105 // options are done, now fill out cmd arg list with remaining args 106 for(int i=currOptIndex; i<args.length; i++){ 107 String token = args[i]; 108 theCmdArgs.add(token); 109 } 110 } 111 112 113 /** 114 * debugging routine to print out all options collected 115 */ 116 public void printOptions(){ 117 for(ListIterator it=theOptions.listIterator(); it.hasNext();){ 118 Option opt = (Option)it.next(); 119 System.out.print("OPT =" + opt.getArgLetter()); 120 String arg = opt.getArgument(); 121 if(arg != null){ 122 System.out.print(" " + arg); 123 } 124 System.out.println(); 125 } 126 } 127 128 /** 129 * gets the next option found in the commandline. Distinguishes 130 * between two bad cases, one case is when an illegal option 131 * is found, and then other case is when an option takes an 132 * argument but no argument was found for that option. 133 * If the option found was not declared in the optString, then 134 * an IllegalArgumentException will be thrown (case 1). 135 * If the next option found has been declared to take an argument, 136 * and no such argument exists, then a MissingOptArgException 137 * is thrown (case 2). 138 * @return int - the next option found. 139 * @throws IllegalArgumentException, MissingOptArgException. 140 */ 141 public int getNextOption() throws IllegalArgumentException, 142 MissingOptArgException 143 { 144 int retval = -1; 145 if(theOptionsIterator.hasNext()){ 146 theCurrentOption = (Option)theOptionsIterator.next(); 147 char c = theCurrentOption.getArgLetter(); 148 boolean shouldHaveArg = theOptionMatcher.hasArg(c); 149 String arg = theCurrentOption.getArgument(); 150 if(!theOptionMatcher.match(c)) { 151 ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_CMDLINE_OPTION_ERR, 152 new Character(c)); 153 throw (new IllegalArgumentException(msg.toString())); 154 } 155 else if(shouldHaveArg && (arg == null)) { 156 ErrorMsg msg = new ErrorMsg(ErrorMsg.CMDLINE_OPT_MISSING_ARG_ERR, 157 new Character(c)); 158 throw (new MissingOptArgException(msg.toString())); 159 } 160 retval = c; 161 } 162 return retval; 163 } 164 165 /** 166 * gets the argument for the current parsed option. For example, 167 * in case of '-d <file>', if current option parsed is 'd' then 168 * getOptionArg() would return '<file>'. 169 * @return String - argument for current parsed option. 170 */ 171 public String getOptionArg(){ 172 String retval = null; 173 String tmp = theCurrentOption.getArgument(); 174 char c = theCurrentOption.getArgLetter(); 175 if(theOptionMatcher.hasArg(c)){ 176 retval = tmp; 177 } 178 return retval; 179 } 180 181 /** 182 * gets list of the commandline arguments. For example, in command 183 * such as 'cmd -s -d file file2 file3 file4' with the usage 184 * 'cmd [-s] [-d <file>] <file>...', getCmdArgs() would return 185 * the list {file2, file3, file4}. 186 * @return String[] - list of command arguments that may appear 187 * after options and option arguments. 188 */ 189 public String[] getCmdArgs(){ 190 String[] retval = new String[theCmdArgs.size()]; 191 int i=0; 192 for(ListIterator it=theCmdArgs.listIterator(); it.hasNext();){ 193 retval[i++] = (String)it.next(); 194 } 195 return retval; 196 } 197 198 199 private Option theCurrentOption = null; 200 private ListIterator theOptionsIterator; 201 private List theOptions = null; 202 private List theCmdArgs = null; 203 private OptionMatcher theOptionMatcher = null; 204 205 /////////////////////////////////////////////////////////// 206 // 207 // Inner Classes 208 // 209 /////////////////////////////////////////////////////////// 210 211 // inner class to model an option 212 static class Option{ 213 private char theArgLetter; 214 private String theArgument = null; 215 public Option(char argLetter) { theArgLetter = argLetter; } 216 public void setArg(String arg) { 217 theArgument = arg; 218 } 219 public boolean hasArg() { return (theArgument != null); } 220 public char getArgLetter() { return theArgLetter; } 221 public String getArgument() { return theArgument; } 222 } // end class Option 223 224 225 // inner class to query optString for a possible option match, 226 // and whether or not a given legal option takes an argument. 227 // 228 static class OptionMatcher{ 229 public OptionMatcher(String optString){ 230 theOptString = optString; 231 } 232 public boolean match(char c){ 233 boolean retval = false; 234 if(theOptString.indexOf(c) != -1){ 235 retval = true; 236 } 237 return retval; 238 } 239 public boolean hasArg(char c){ 240 boolean retval = false; 241 int index = theOptString.indexOf(c)+1; 242 if (index == theOptString.length()){ 243 // reached end of theOptString 244 retval = false; 245 } 246 else if(theOptString.charAt(index) == ':'){ 247 retval = true; 248 } 249 return retval; 250 } 251 private String theOptString = null; 252 } // end class OptionMatcher 253 }// end class GetOpt 254