1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.cli2.commandline;
18
19 import java.util.LinkedList;
20 import java.util.List;
21 import java.util.ListIterator;
22
23 import org.apache.commons.cli2.CommandLine;
24 import org.apache.commons.cli2.Group;
25 import org.apache.commons.cli2.Option;
26 import org.apache.commons.cli2.OptionException;
27 import org.apache.commons.cli2.WriteableCommandLine;
28 import org.apache.commons.cli2.resource.ResourceConstants;
29 import org.apache.commons.cli2.util.HelpFormatter;
30
31 /**
32 * A class that implements the <code>Parser</code> interface can parse a
33 * String array according to the {@link Group}specified and return a
34 * {@link CommandLine}.
35 *
36 * @author John Keyes (john at integralsource.com)
37 */
38 public class Parser {
39 private HelpFormatter helpFormatter = new HelpFormatter();
40 private Option helpOption = null;
41 private String helpTrigger = null;
42 private Group group = null;
43
44 /**
45 * Parse the arguments according to the specified options and properties.
46 *
47 * @param arguments
48 * the command line arguments
49 *
50 * @return the list of atomic option and value tokens
51 * @throws OptionException
52 * if there are any problems encountered while parsing the
53 * command line tokens.
54 */
55 public CommandLine parse(final String[] arguments)
56 throws OptionException {
57 // build a mutable list for the arguments
58 final List argumentList = new LinkedList();
59
60 // copy the arguments into the new list
61 for (int i = 0; i < arguments.length; i++) {
62 final String argument = arguments[i];
63
64 // ensure non intern'd strings are used
65 // so that == comparisons work as expected
66 argumentList.add(new String(argument));
67 }
68
69 // wet up a command line for this group
70 final WriteableCommandLine commandLine = new WriteableCommandLineImpl(group, argumentList);
71
72 // pick up any defaults from the model
73 group.defaults(commandLine);
74
75 // process the options as far as possible
76 final ListIterator iterator = argumentList.listIterator();
77 Object previous = null;
78
79 while (group.canProcess(commandLine, iterator)) {
80 // peek at the next item and backtrack
81 final Object next = iterator.next();
82 iterator.previous();
83
84 // if we have just tried to process this instance
85 if (next == previous) {
86 // abort
87 break;
88 }
89
90 // remember previous
91 previous = next;
92
93 group.process(commandLine, iterator);
94 }
95
96 // if there are more arguments we have a problem
97 if (iterator.hasNext()) {
98 final String arg = (String) iterator.next();
99 throw new OptionException(group, ResourceConstants.UNEXPECTED_TOKEN, arg);
100 }
101
102 // no need to validate if the help option is present
103 if (!commandLine.hasOption(helpOption) && !commandLine.hasOption(helpTrigger)) {
104 group.validate(commandLine);
105 }
106
107 return commandLine;
108 }
109
110 /**
111 * Parse the arguments according to the specified options and properties and
112 * displays the usage screen if the CommandLine is not valid or the help
113 * option was specified.
114 *
115 * @param arguments the command line arguments
116 * @return a valid CommandLine or null if the parse was unsuccessful
117 */
118 public CommandLine parseAndHelp(final String[] arguments) {
119 helpFormatter.setGroup(group);
120
121 try {
122 // attempt to parse the command line
123 final CommandLine commandLine = parse(arguments);
124
125 if (!commandLine.hasOption(helpOption) && !commandLine.hasOption(helpTrigger)) {
126 return commandLine;
127 }
128 } catch (final OptionException oe) {
129 // display help regarding the exception
130 helpFormatter.setException(oe);
131 }
132
133 // print help
134 helpFormatter.print();
135
136 return null;
137 }
138
139 /**
140 * Sets the Group of options to parse against
141 * @param group the group of options to parse against
142 */
143 public void setGroup(final Group group) {
144 this.group = group;
145 }
146
147 /**
148 * Sets the HelpFormatter to use with the simplified parsing.
149 * @see #parseAndHelp(String[])
150 * @param helpFormatter the HelpFormatter to use with the simplified parsing
151 */
152 public void setHelpFormatter(final HelpFormatter helpFormatter) {
153 this.helpFormatter = helpFormatter;
154 }
155
156 /**
157 * Sets the help option to use with the simplified parsing. For example
158 * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used.
159 * @see #parseAndHelp(String[])
160 * @param helpOption the help Option
161 */
162 public void setHelpOption(final Option helpOption) {
163 this.helpOption = helpOption;
164 }
165
166 /**
167 * Sets the help option to use with the simplified parsing. For example
168 * <code>--help</code>, <code>-h</code> and <code>-?</code> are often used.
169 * @see #parseAndHelp(String[])
170 * @param helpTrigger the trigger of the help Option
171 */
172 public void setHelpTrigger(final String helpTrigger) {
173 this.helpTrigger = helpTrigger;
174 }
175 }