com.alibaba.antx.util.cli.PosixParser Maven / Gradle / Ivy
/*
* Copyright (c) 2002-2012 Alibaba Group Holding Limited.
* All rights reserved.
*
* Licensed 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 com.alibaba.antx.util.cli;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
/**
* The class PosixParser provides an implementation of the
* {@link Parser#flatten(Options, String[], boolean) flatten} method.
*
* @author John Keyes (john at integralsource.com)
* @see Parser
*/
public class PosixParser extends Parser {
/** holder for flattened tokens */
private ArrayList 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, set eatTheRest
to false and set
* currentOption
to null.
*
*/
private void init() {
eatTheRest = false;
tokens.clear();
currentOption = null;
}
/**
*
* 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 PosixParser#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.
*/
@Override
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();
String token = null;
// process each command line token
while (iter.hasNext()) {
// get the next command line token
token = (String) iter.next();
// handle SPECIAL TOKEN
if (token.startsWith("--")) {
if (token.indexOf('=') != -1) {
tokens.add(token.substring(0, token.indexOf('=')));
tokens.add(token.substring(token.indexOf('=') + 1, token.length()));
} else {
processOptionToken(token, stopAtNonOption);
//tokens.add(token);
}
}
// single hyphen
else if ("-".equals(token)) {
processSingleHyphen(token);
} else if (token.startsWith("-")) {
int tokenLength = token.length();
if (tokenLength == 2) {
processOptionToken(token, stopAtNonOption);
}
// requires bursting
else {
burstToken(token, stopAtNonOption);
}
} else {
if (stopAtNonOption) {
process(token);
} else {
tokens.add(token);
}
}
gobble(iter);
}
return (String[]) tokens.toArray(new String[] { });
}
/**
*
* 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());
}
}
}
/**
*
* If there is a current option and it can have an argument value then add
* the token to the processed tokens list and set the current option to
* null.
*
*
* If there is a current option and it can have argument values then add the
* token to the processed tokens list.
*
*
* If there is not a current option add the special token "--" and
* the current value
to the processed tokens list. The add all
* the remaining argument
values to the processed tokens list.
*
*
* @param value The current token
*/
private void process(String value) {
if (currentOption != null && currentOption.hasArg()) {
if (currentOption.hasArg()) {
tokens.add(value);
currentOption = null;
} else if (currentOption.hasArgs()) {
tokens.add(value);
}
} else {
eatTheRest = true;
tokens.add("--");
tokens.add(value);
}
}
/**
*
* If it is a hyphen then add the hyphen directly to the processed tokens
* list.
*
*
* @param hyphen The hyphen token
*/
private void processSingleHyphen(String hyphen) {
tokens.add(hyphen);
}
/**
*
* If an {@link Option} exists for token
then set the current
* option and add the token to the processed list.
*
*
* If an {@link Option} does not exist and stopAtNonOption
is
* set then ignore the current token and 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 (this.options.hasOption(token)) {
currentOption = this.options.getOption(token);
tokens.add(token);
} else if (stopAtNonOption) {
eatTheRest = true;
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 "-".
*
*
*/
protected void burstToken(String token, boolean stopAtNonOption) {
int tokenLength = token.length();
for (int i = 1; i < tokenLength; i++) {
String ch = String.valueOf(token.charAt(i));
boolean hasOption = options.hasOption(ch);
if (hasOption) {
tokens.add("-" + ch);
currentOption = options.getOption(ch);
if (currentOption.hasArg() && token.length() != i + 1) {
tokens.add(token.substring(i + 1));
break;
}
} else if (stopAtNonOption) {
process(token.substring(i));
} else {
tokens.add("-" + ch);
}
}
}
}