001    /*--------------------------------------------------------------------------+
002    $Id: CommandLineTokenStream.java 26283 2010-02-18 11:18:57Z juergens $
003    |                                                                          |
004    | Copyright 2005-2010 Technische Universitaet Muenchen                     |
005    |                                                                          |
006    | Licensed 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    package edu.tum.cs.commons.options;
019    
020    import java.util.LinkedList;
021    import java.util.Queue;
022    
023    /**
024     * This class preprocesses the command line arguments by splitting them into
025     * several tokens. It supports the GNU style syntax as described in
026     * {@link edu.tum.cs.commons.options.CommandLine}.
027     * 
028     * @author Benjamin Hummel
029     * @author $Author: juergens $
030     * 
031     * @version $Rev: 26283 $
032     * @levd.rating GREEN Hash: D702FFBA7BE4D5C8637EEE2993924D3B
033     */
034    public class CommandLineTokenStream {
035    
036            /** Queue storing remaining short options (results from option chaining). */
037            private final Queue<Character> shortOptionQueue = new LinkedList<Character>();
038    
039            /** Pending parameter (possibly remaining from the last long option read). */
040            private String pendingParam = null;
041    
042            /** Queue storing all remaining arguments. */
043            private final Queue<String> argQueue = new LinkedList<String>();
044    
045            /**
046             * Constructs a new CommandLineTokenStream on the given arguments.
047             * 
048             * @param args
049             */
050            public CommandLineTokenStream(String[] args) {
051                    for (String a : args) {
052                            argQueue.add(a);
053                    }
054            }
055    
056            /**
057             * Returns whether a further token is available.
058             */
059            public boolean hasNext() {
060                    return !argQueue.isEmpty() || !shortOptionQueue.isEmpty()
061                                    || pendingParam != null;
062            }
063    
064            /**
065             * Returns whether the next token is available and is a short option.
066             */
067            public boolean nextIsShortOption() {
068                    if (!shortOptionQueue.isEmpty()) {
069                            return true;
070                    }
071                    if (pendingParam != null || argQueue.isEmpty()) {
072                            return false;
073                    }
074                    String next = argQueue.peek();
075                    return next.length() >= 2 && next.charAt(0) == '-'
076                                    && next.charAt(1) != '-';
077            }
078    
079            /**
080             * Returns whether the next token is available and is a long option.
081             */
082            public boolean nextIsLongOption() {
083                    if (!shortOptionQueue.isEmpty() || pendingParam != null
084                                    || argQueue.isEmpty()) {
085                            return false;
086                    }
087                    return argQueue.peek().startsWith("--");
088            }
089    
090            /**
091             * Returns whether the next token is available and can be used as a file
092             * argument.
093             */
094            public boolean nextIsFileArgument() {
095                    if (!shortOptionQueue.isEmpty() || pendingParam != null
096                                    || argQueue.isEmpty()) {
097                            return false;
098                    }
099                    return !argQueue.peek().startsWith("-");
100            }
101    
102            /**
103             * Returns whether the next token is available and can be used as a
104             * parameter to an option.
105             */
106            public boolean nextIsParameter() {
107                    if (!shortOptionQueue.isEmpty()) {
108                            return false;
109                    }
110                    if (pendingParam != null) {
111                            return true;
112                    }
113                    return !argQueue.isEmpty();
114            }
115    
116            /**
117             * Returns the next token as a plain string.
118             */
119            public String next() {
120                    if (!shortOptionQueue.isEmpty()) {
121                            return "-" + shortOptionQueue.poll();
122                    }
123                    if (pendingParam != null) {
124                            String result = pendingParam;
125                            pendingParam = null;
126                            return result;
127                    }
128                    return argQueue.poll();
129            }
130    
131            /**
132             * Returns the next token as a short option.
133             */
134            public char nextShortOption() {
135                    if (!nextIsShortOption()) {
136                            throw new IllegalStateException("No short option available!");
137                    }
138                    if (shortOptionQueue.isEmpty()) {
139                            String arg = argQueue.poll();
140                            for (int i = 1; i < arg.length(); ++i) {
141                                    shortOptionQueue.add(arg.charAt(i));
142                            }
143                    }
144                    return shortOptionQueue.poll();
145            }
146    
147            /**
148             * Returns the next token as a long option.
149             */
150            public String nextLongOption() {
151                    if (!nextIsLongOption()) {
152                            throw new IllegalStateException("No long option available!");
153                    }
154                    String res = argQueue.poll().substring(2);
155                    if (res.contains("=")) {
156                            String[] parts = res.split("=", 2);
157                            res = parts[0];
158                            pendingParam = parts[1];
159                    }
160                    return res;
161            }
162    }