eu.tneitzel.argparse4j.internal.ArgumentImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of argparse4j Show documentation
Show all versions of argparse4j Show documentation
Fork of the popular command line parser library argparse4j
The newest version!
/*
* Copyright (C) 2011 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package eu.tneitzel.argparse4j.internal;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
import eu.tneitzel.argparse4j.helper.MessageLocalization;
import eu.tneitzel.argparse4j.helper.TextHelper;
import eu.tneitzel.argparse4j.helper.TextWidthCounter;
import eu.tneitzel.argparse4j.impl.Arguments;
import eu.tneitzel.argparse4j.impl.choice.CollectionArgumentChoice;
import eu.tneitzel.argparse4j.impl.type.ReflectArgumentType;
import eu.tneitzel.argparse4j.impl.type.StringArgumentType;
import eu.tneitzel.argparse4j.inf.Argument;
import eu.tneitzel.argparse4j.inf.ArgumentAction;
import eu.tneitzel.argparse4j.inf.ArgumentChoice;
import eu.tneitzel.argparse4j.inf.ArgumentParserException;
import eu.tneitzel.argparse4j.inf.ArgumentType;
import eu.tneitzel.argparse4j.inf.FeatureControl;
import eu.tneitzel.argparse4j.inf.MetavarInference;
/**
* The application code must not use this class directly.
*/
public final class ArgumentImpl implements Argument {
private String name_;
private String[] flags_;
private String dest_;
private ArgumentType> type_ = new StringArgumentType();
private ArgumentAction action_ = Arguments.store();
private ArgumentChoice choice_;
private Object const_;
private Object default_;
private FeatureControl defaultControl_;
private FeatureControl helpControl_;
private boolean required_;
private String[] metavar_;
private int minNumArg_ = -1;
private int maxNumArg_ = -1;
private String help_ = "";
private final ArgumentParserConfigurationImpl config_;
private final ArgumentGroupImpl argumentGroup_;
ArgumentImpl(ArgumentParserConfigurationImpl config,
String... nameOrFlags) {
this(config, null, nameOrFlags);
}
ArgumentImpl(ArgumentParserConfigurationImpl config,
ArgumentGroupImpl argumentGroup, String... nameOrFlags) {
if (nameOrFlags.length == 0) {
throw new IllegalArgumentException("no nameOrFlags was specified");
}
config_ = config;
argumentGroup_ = argumentGroup;
if (nameOrFlags.length == 1
&& !config.prefixPattern_.match(nameOrFlags[0])) {
if (argumentGroup_ != null && argumentGroup_.isMutex()) {
throw new IllegalArgumentException(
"mutually exclusive arguments must be optional");
}
name_ = nameOrFlags[0];
if (!config.noDestConversionForPositionalArgs_) {
dest_ = name_.replace('-', '_');
}
} else {
flags_ = nameOrFlags;
for (String flag : flags_) {
if (!config.prefixPattern_.match(flag)) {
throw new IllegalArgumentException(
String.format(
TextHelper.LOCALE_ROOT,
localize("invalidOptionStringError"),
flag, config.prefixPattern_.getPrefixChars()));
}
}
String flagToBaseDestOn = getPrimaryFlag();
dest_ = config.prefixPattern_.removePrefix(flagToBaseDestOn).replace('-', '_');
}
}
String getPrimaryFlag() {
String result = null;
for (String flag : flags_) {
boolean longFlag = config_.prefixPattern_.matchLongFlag(flag);
if (result == null) {
result = flag;
if (longFlag) {
break;
}
} else if (longFlag) {
result = flag;
break;
}
}
return result;
}
@Override
public String textualName() {
return name_ == null ? TextHelper.concat(flags_, 0, "/") : name_;
}
/**
* Short syntax is used in usage message, e.g. --foo BAR
*
* @return short syntax
*/
String formatShortSyntax() {
if (name_ == null) {
StringBuilder sb = new StringBuilder();
if (!required_) {
sb.append("[");
}
sb.append(flags_[0]);
String mv = formatMetavar();
if (!mv.isEmpty()) {
sb.append(" ").append(mv);
}
if (!required_) {
sb.append("]");
}
return sb.toString();
} else {
return formatMetavar();
}
}
/**
* Short syntax is used in usage message, e.g. --foo BAR, but without
* bracket when this is not required option.
*
* @return short syntax
*/
String formatShortSyntaxNoBracket() {
if (name_ == null) {
StringBuilder sb = new StringBuilder();
sb.append(flags_[0]);
String mv = formatMetavar();
if (!mv.isEmpty()) {
sb.append(" ").append(mv);
}
return sb.toString();
} else {
return formatMetavar();
}
}
String[] resolveMetavar() {
if (metavar_ == null) {
if (choice_ == null) {
if (type_ instanceof MetavarInference) {
String[] metavar = ((MetavarInference) type_)
.inferMetavar();
if (metavar != null) {
return metavar;
}
}
if (isNamedArgument()) {
return new String[] { dest_.toUpperCase() };
}
return new String[] { dest_ };
}
return new String[] { choice_.textualFormat() };
}
return metavar_;
}
String formatMetavar() {
StringBuilder sb = new StringBuilder();
if (action_.consumeArgument()) {
String[] metavar = resolveMetavar();
if (minNumArg_ == 0 && maxNumArg_ == 1) {
sb.append("[").append(metavar[0]).append("]");
} else if (minNumArg_ == 0 && maxNumArg_ == Integer.MAX_VALUE) {
sb.append("[").append(metavar[0]).append(" [")
.append(metavar.length == 1 ? metavar[0] : metavar[1])
.append(" ...]]");
} else if (minNumArg_ == 1 && maxNumArg_ == Integer.MAX_VALUE) {
sb.append(metavar[0]).append(" [")
.append(metavar.length == 1 ? metavar[0] : metavar[1])
.append(" ...]");
} else if (minNumArg_ == -1) {
sb.append(metavar[0]);
} else if (minNumArg_ > 0 && minNumArg_ == maxNumArg_) {
int i, max;
for (i = 0, max = Math.min(minNumArg_, metavar.length); i < max; ++i) {
sb.append(metavar[i]).append(" ");
}
for (; i < minNumArg_; ++i) {
sb.append(metavar[metavar.length - 1]).append(" ");
}
sb.delete(sb.length() - 1, sb.length());
}
}
return sb.toString();
}
private String formatHelpTitle() {
if (isNamedArgument()) {
String mv = formatMetavar();
StringBuilder sb = new StringBuilder();
if(config_.singleMetavar_) {
for (String flag : flags_) {
if(sb.length() > 0) {
sb.append(", ");
}
sb.append(flag);
}
if (!mv.isEmpty()) {
sb.append(" ").append(mv);
}
} else {
for (String flag : flags_) {
sb.append(flag);
if (!mv.isEmpty()) {
sb.append(" ").append(mv);
}
sb.append(", ");
}
if (sb.length() > 2) {
sb.delete(sb.length() - 2, sb.length());
}
}
return sb.toString();
} else {
return resolveMetavar()[0];
}
}
public void printHelp(PrintWriter writer, boolean defaultHelp,
TextWidthCounter textWidthCounter, int width) {
if (helpControl_ == Arguments.SUPPRESS) {
return;
}
String help;
if (defaultHelp && default_ != null) {
StringBuilder sb = new StringBuilder(help_);
if (!help_.isEmpty()) {
sb.append(" ");
}
sb.append("(").append(localize("default")).append(" ")
.append(default_.toString()).append(")");
help = sb.toString();
} else {
help = help_;
}
TextHelper.printHelp(writer, formatHelpTitle(), help, textWidthCounter,
width);
}
public Object convert(ArgumentParserImpl parser, String value)
throws ArgumentParserException {
Object obj = type_.convert(parser, this, value);
if (choice_ != null && !choice_.contains(obj)) {
throw new ArgumentParserException(String.format(
TextHelper.LOCALE_ROOT, localize("invalidChoiceError"),
value, choice_.textualFormat()), parser, this);
}
return obj;
}
@Override
public ArgumentImpl nargs(int n) {
if (n <= 0) {
throw new IllegalArgumentException("nargs must be positive integer");
}
minNumArg_ = maxNumArg_ = n;
return this;
}
@Override
public ArgumentImpl nargs(String n) {
switch (n) {
case "*":
minNumArg_ = 0;
maxNumArg_ = Integer.MAX_VALUE;
break;
case "+":
minNumArg_ = 1;
maxNumArg_ = Integer.MAX_VALUE;
break;
case "?":
minNumArg_ = 0;
maxNumArg_ = 1;
break;
default:
throw new IllegalArgumentException(
"narg expects positive integer or one of '*', '+' or '?'");
}
return this;
}
@Override
public ArgumentImpl setConst(Object value) {
// Allow null
const_ = value;
return this;
}
@SafeVarargs
@Override
public final ArgumentImpl setConst(E... values) {
// Allow null
const_ = Arrays.asList(values);
return this;
}
@Override
public ArgumentImpl setDefault(Object value) {
// Allow null
default_ = value;
return this;
}
@SafeVarargs
@Override
public final ArgumentImpl setDefault(E... values) {
// Allow null
default_ = Arrays.asList(values);
return this;
}
@Override
public ArgumentImpl setDefault(FeatureControl ctrl) {
defaultControl_ = ctrl;
return this;
}
private ReflectArgumentType createReflectArgumentType(Class type) {
return new ReflectArgumentType<>(type);
}
@Override
public ArgumentImpl type(Class type) {
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
if (type.isPrimitive()) {
// Convert primitive type class to its object counterpart
if (type == boolean.class) {
type_ = createReflectArgumentType(Boolean.class);
} else if (type == byte.class) {
type_ = createReflectArgumentType(Byte.class);
} else if (type == short.class) {
type_ = createReflectArgumentType(Short.class);
} else if (type == int.class) {
type_ = createReflectArgumentType(Integer.class);
} else if (type == long.class) {
type_ = createReflectArgumentType(Long.class);
} else if (type == float.class) {
type_ = createReflectArgumentType(Float.class);
} else if (type == double.class) {
type_ = createReflectArgumentType(Double.class);
} else {
// void and char are not supported.
// char.class does not have valueOf(String) method
throw new IllegalArgumentException("unexpected primitive type");
}
} else {
type_ = createReflectArgumentType(type);
}
return this;
}
@Override
public ArgumentImpl type(ArgumentType type) {
if (type == null) {
throw new IllegalArgumentException("type cannot be null");
}
type_ = type;
return this;
}
@Override
public ArgumentImpl required(boolean required) {
required_ = required;
return this;
}
@Override
public ArgumentImpl action(ArgumentAction action) {
if (action == null) {
throw new IllegalArgumentException("action cannot be null");
}
action_ = action;
action_.onAttach(this);
return this;
}
@Override
public ArgumentImpl choices(ArgumentChoice choice) {
if (choice == null) {
throw new IllegalArgumentException("choice cannot be null");
}
choice_ = choice;
return this;
}
@Override
public ArgumentImpl choices(Collection values) {
if (values == null) {
throw new IllegalArgumentException("choice cannot be null");
}
choice_ = new CollectionArgumentChoice<>(values);
return this;
}
@SafeVarargs
@Override
public final ArgumentImpl choices(E... values) {
if (values == null) {
throw new IllegalArgumentException("choice cannot be null");
}
choice_ = new CollectionArgumentChoice<>(values);
return this;
}
@Override
public ArgumentImpl dest(String dest) {
if (dest == null) {
throw new IllegalArgumentException("dest cannot be null");
}
dest_ = dest;
return this;
}
@Override
public ArgumentImpl metavar(String... metavar) {
if (metavar.length == 0) {
throw new IllegalArgumentException("No metavar specified");
}
for (String m : metavar) {
if (m == null) {
throw new IllegalArgumentException("metavar cannot be null");
}
}
metavar_ = metavar;
return this;
}
@Override
public ArgumentImpl help(String help) {
help_ = TextHelper.nonNull(help);
return this;
}
@Override
public ArgumentImpl help(FeatureControl ctrl) {
helpControl_ = ctrl;
return this;
}
boolean isNamedArgument() {
return name_ == null;
}
public void run(ArgumentParserImpl parser, Map res,
String flag, Object value, Consumer