org.codehaus.groovy.cli.GroovyPosixParser Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.cli;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.Parser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* DO NOT USE. Hacked version until Commons CLI 1.3 is released.
* NOTE: this is a mirror copy of org.apache.commons.cli.GroovyInternalPosixParser
* DON'T MAKE CHANGES without keeping the other file in sync!
* The class GroovyPosixParser provides an implementation of the
* {@link org.apache.commons.cli.Parser#flatten(org.apache.commons.cli.Options,String[],boolean) flatten} method.
*
* @author John Keyes (john at integralsource.com)
* @author Paul King (Groovy hacks/fixes)
*/
public class GroovyPosixParser extends Parser
{
/** holder for flattened tokens */
private List tokens = new ArrayList();
/** specifies if bursting should continue */
private boolean eatTheRest;
/** holder for the current option */
private Option currentOption;
/** the command line Options */
private Options options;
/**
* Resets the members to their original state i.e. remove
* all of tokens
entries and set eatTheRest
* to false.
*/
private void init()
{
eatTheRest = false;
tokens.clear();
}
/**
* An implementation of {@link Parser}'s abstract
* {@link Parser#flatten(Options,String[],boolean) flatten} method.
*
* The following are the rules used by this flatten method.
*
* - if
stopAtNonOption
is true then do not
* burst anymore of arguments
entries, just add each
* successive entry without further processing. Otherwise, ignore
* stopAtNonOption
.
* - if the current
arguments
entry is "--"
* just add the entry to the list of processed tokens
* - if the current
arguments
entry is "-"
* just add the entry to the list of processed tokens
* - if the current
arguments
entry is two characters
* in length and the first character is "-" then check if this
* is a valid {@link Option} id. If it is a valid id, then add the
* entry to the list of processed tokens and set the current {@link Option}
* member. If it is not a valid id and stopAtNonOption
* is true, then the remaining entries are copied to the list of
* processed tokens. Otherwise, the current entry is ignored.
* - if the current
arguments
entry is more than two
* characters in length and the first character is "-" then
* we need to burst the entry to determine its constituents. For more
* information on the bursting algorithm see
* {@link GroovyPosixParser#burstToken(String, boolean) burstToken}.
* - if the current
arguments
entry is not handled
* by any of the previous rules, then the entry is added to the list
* of processed tokens.
*
*
* @param options The command line {@link Options}
* @param arguments The command line arguments to be parsed
* @param stopAtNonOption Specifies whether to stop flattening when an non option is found.
* @return The flattened arguments
String array.
*/
protected String[] flatten(Options options, String[] arguments, boolean stopAtNonOption) {
init();
this.options = options;
// an iterator for the command line tokens
Iterator iter = Arrays.asList(arguments).iterator();
// process each command line token
while (iter.hasNext())
{
// get the next command line token
String token = (String) iter.next();
// handle long option --foo or --foo=bar
if (token.startsWith("--"))
{
int pos = token.indexOf('=');
String opt = pos == -1 ? token : token.substring(0, pos); // --foo
if (!options.hasOption(opt))
{
processNonOptionToken(token, stopAtNonOption);
}
else
{
tokens.add(opt);
if (pos != -1)
{
tokens.add(token.substring(pos + 1));
} else {
currentOption = options.getOption(opt);
}
}
}
// single hyphen
else if ("-".equals(token))
{
tokens.add(token);
}
else if (token.startsWith("-"))
{
if (token.length() == 2 || options.hasOption(token))
{
processOptionToken(token, stopAtNonOption);
}
// requires bursting
else
{
burstToken(token, stopAtNonOption);
}
}
else
{
processNonOptionToken(token, stopAtNonOption);
}
gobble(iter);
}
return (String[]) tokens.toArray(new String[tokens.size()]);
}
/**
* Adds the remaining tokens to the processed tokens list.
*
* @param iter An iterator over the remaining tokens
*/
private void gobble(Iterator iter)
{
if (eatTheRest)
{
while (iter.hasNext())
{
tokens.add(iter.next());
}
}
}
/**
* Add the special token "--" and the current value
* to the processed tokens list. Then add all the remaining
* argument
values to the processed tokens list.
*
* @param value The current token
*/
private void processNonOptionToken(String value, boolean stopAtNonOption)
{
if (stopAtNonOption && (currentOption == null || !currentOption.hasArg()))
{
eatTheRest = true;
tokens.add("--");
}
tokens.add(value);
currentOption = null;
}
/**
* If an {@link Option} exists for token
then
* add the token to the processed list.
*
* If an {@link Option} does not exist and stopAtNonOption
* is set then add the remaining tokens to the processed tokens list
* directly.
*
* @param token The current option token
* @param stopAtNonOption Specifies whether flattening should halt at the first non option.
*/
private void processOptionToken(String token, boolean stopAtNonOption) {
if (stopAtNonOption && !options.hasOption(token))
{
eatTheRest = true;
}
if (options.hasOption(token)) {
currentOption = options.getOption(token);
} else {
currentOption = null;
}
tokens.add(token);
}
/**
* Breaks token
into its constituent parts
* using the following algorithm.
*
*
* - ignore the first character ("-")
* - foreach remaining character check if an {@link Option}
* exists with that id.
* - if an {@link Option} does exist then add that character
* prepended with "-" to the list of processed tokens.
* - if the {@link Option} can have an argument value and there
* are remaining characters in the token then add the remaining
* characters as a token to the list of processed tokens.
* - if an {@link Option} does NOT exist AND
*
stopAtNonOption
IS set then add the special token
* "--" followed by the remaining characters and also
* the remaining tokens directly to the processed tokens list.
* - if an {@link Option} does NOT exist AND
*
stopAtNonOption
IS NOT set then add that
* character prepended with "-".
*
*
* @param token The current token to be burst
* @param stopAtNonOption Specifies whether to stop processing
* at the first non-Option encountered.
*/
protected void burstToken(String token, boolean stopAtNonOption)
{
for (int i = 1; i < token.length(); i++)
{
String ch = String.valueOf(token.charAt(i));
if (options.hasOption(ch))
{
tokens.add("-" + ch);
currentOption = options.getOption(ch);
if (currentOption.hasArg() && (token.length() != (i + 1)))
{
tokens.add(token.substring(i + 1));
break;
}
}
else if (stopAtNonOption)
{
processNonOptionToken(token.substring(i), true);
break;
}
else
{
tokens.add(token);
break;
}
}
}
}