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