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