
net.sourceforge.argparse4j.internal.ArgumentParserImpl 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
The command-line parser library based on Python's argparse
/*
* 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 net.sourceforge.argparse4j.internal;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.annotation.Arg;
import net.sourceforge.argparse4j.helper.ASCIITextWidthCounter;
import net.sourceforge.argparse4j.helper.PrefixPattern;
import net.sourceforge.argparse4j.helper.ReflectHelper;
import net.sourceforge.argparse4j.helper.TextHelper;
import net.sourceforge.argparse4j.helper.TextWidthCounter;
import net.sourceforge.argparse4j.impl.Arguments;
import net.sourceforge.argparse4j.inf.Argument;
import net.sourceforge.argparse4j.inf.ArgumentGroup;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparsers;
/**
* The application code must not use this class directly.
*
*/
public final class ArgumentParserImpl implements ArgumentParser {
private Map optargIndex_ = new HashMap();
private List optargs_ = new ArrayList();
private List posargs_ = new ArrayList();
private List arggroups_ = new ArrayList();
private Map defaults_ = new HashMap();
private SubparsersImpl subparsers_ = new SubparsersImpl(this);
private ArgumentParserImpl mainParser_;
private String command_;
private String prog_;
private String usage_ = "";
private String description_ = "";
private String epilog_ = "";
private String version_ = "";
private PrefixPattern prefixPattern_;
private PrefixPattern fromFilePrefixPattern_;
private boolean defaultHelp_ = false;
private boolean negNumFlag_ = false;
private TextWidthCounter textWidthCounter_;
private static final Pattern NEG_NUM_PATTERN = Pattern.compile("-\\d+");
private static final Pattern SHORT_OPTS_PATTERN = Pattern
.compile("-[^-].*");
public ArgumentParserImpl(String prog) {
this(prog, true, ArgumentParsers.DEFAULT_PREFIX_CHARS, null,
new ASCIITextWidthCounter(), null, null);
}
public ArgumentParserImpl(String prog, boolean addHelp) {
this(prog, addHelp, ArgumentParsers.DEFAULT_PREFIX_CHARS, null,
new ASCIITextWidthCounter(), null, null);
}
public ArgumentParserImpl(String prog, boolean addHelp, String prefixChars) {
this(prog, addHelp, prefixChars, null, new ASCIITextWidthCounter(),
null, null);
}
public ArgumentParserImpl(String prog, boolean addHelp, String prefixChars,
String fromFilePrefix) {
this(prog, addHelp, prefixChars, fromFilePrefix,
new ASCIITextWidthCounter(), null, null);
}
public ArgumentParserImpl(String prog, boolean addHelp, String prefixChars,
String fromFilePrefix, TextWidthCounter textWidthCounter) {
this(prog, addHelp, prefixChars, fromFilePrefix, textWidthCounter,
null, null);
}
public ArgumentParserImpl(String prog, boolean addHelp, String prefixChars,
String fromFilePrefix, TextWidthCounter textWidthCounter,
String command, ArgumentParserImpl mainParser) {
this.prog_ = TextHelper.nonNull(prog);
this.command_ = command;
this.mainParser_ = mainParser;
this.textWidthCounter_ = textWidthCounter;
if (prefixChars == null || prefixChars.isEmpty()) {
throw new IllegalArgumentException(
"prefixChars cannot be a null or empty");
}
this.prefixPattern_ = new PrefixPattern(prefixChars);
if (fromFilePrefix != null) {
this.fromFilePrefixPattern_ = new PrefixPattern(fromFilePrefix);
}
if (addHelp) {
String prefix = prefixChars.substring(0, 1);
addArgument(prefix + "h", prefix + prefix + "help")
.action(Arguments.help())
.help("show this help message and exit")
.setDefault(Arguments.SUPPRESS);
}
}
@Override
public ArgumentImpl addArgument(String... nameOrFlags) {
return addArgument(null, nameOrFlags);
}
public ArgumentImpl addArgument(ArgumentGroupImpl group,
String... nameOrFlags) {
ArgumentImpl arg = new ArgumentImpl(prefixPattern_, group, nameOrFlags);
if (arg.isOptionalArgument()) {
for (String flag : arg.getFlags()) {
ArgumentImpl another = optargIndex_.get(flag);
if (another != null) {
// TODO No conflict handler ATM
throw new IllegalArgumentException(String.format(
"argument %s: conflicting option string(s): %s",
flag, another.textualName()));
}
}
for (String flag : arg.getFlags()) {
if (NEG_NUM_PATTERN.matcher(flag).matches()) {
negNumFlag_ = true;
}
optargIndex_.put(flag, arg);
}
optargs_.add(arg);
} else {
for (ArgumentImpl another : posargs_) {
if (arg.getName().equals(another.getName())) {
// TODO No conflict handler ATM
throw new IllegalArgumentException(String.format(
"argument %s: conflicting option string(s): %s",
arg.getName(), another.textualName()));
}
}
posargs_.add(arg);
}
return arg;
}
@Override
public SubparsersImpl addSubparsers() {
return subparsers_;
}
@Override
public ArgumentGroup addArgumentGroup(String title) {
ArgumentGroupImpl group = new ArgumentGroupImpl(this, title);
group.setIndex(arggroups_.size());
arggroups_.add(group);
return group;
}
@Override
public MutuallyExclusiveGroup addMutuallyExclusiveGroup() {
return addMutuallyExclusiveGroup("");
}
@Override
public MutuallyExclusiveGroup addMutuallyExclusiveGroup(String title) {
ArgumentGroupImpl group = new ArgumentGroupImpl(this, title);
group.setIndex(arggroups_.size());
group.setMutex(true);
arggroups_.add(group);
return group;
}
@Override
public ArgumentParserImpl usage(String usage) {
usage_ = TextHelper.nonNull(usage);
return this;
}
/**
* Set text to display before the argument help.
*
* @param description
* text to display before the argument help
* @return this
*/
@Override
public ArgumentParserImpl description(String description) {
description_ = TextHelper.nonNull(description);
return this;
}
@Override
public ArgumentParserImpl epilog(String epilog) {
epilog_ = TextHelper.nonNull(epilog);
return this;
}
@Override
public ArgumentParserImpl version(String version) {
version_ = TextHelper.nonNull(version);
return this;
}
@Override
public ArgumentParserImpl defaultHelp(boolean defaultHelp) {
defaultHelp_ = defaultHelp;
return this;
}
public boolean isDefaultHelp() {
return defaultHelp_;
}
private void printArgumentHelp(PrintWriter writer, List args,
int format_width) {
for (ArgumentImpl arg : args) {
if (arg.getArgumentGroup() == null
|| !arg.getArgumentGroup().isSeparateHelp()) {
arg.printHelp(writer, defaultHelp_, textWidthCounter_,
format_width);
}
}
}
@Override
public void printHelp() {
PrintWriter writer = new PrintWriter(System.out);
printHelp(writer);
writer.close();
}
@Override
public void printHelp(PrintWriter writer) {
int formatWidth = ArgumentParsers.getFormatWidth();
printUsage(writer, formatWidth);
if (!description_.isEmpty()) {
writer.format("%n%s%n", TextHelper.wrap(textWidthCounter_,
description_, formatWidth, 0, "", ""));
}
boolean subparsersUntitled = subparsers_.getTitle().isEmpty()
&& subparsers_.getDescription().isEmpty();
if (checkDefaultGroup(posargs_)
|| (subparsers_.hasSubCommand() && subparsersUntitled)) {
writer.format("%npositional arguments:%n");
printArgumentHelp(writer, posargs_, formatWidth);
if (subparsers_.hasSubCommand() && subparsersUntitled) {
subparsers_.printSubparserHelp(writer, formatWidth);
}
}
if (checkDefaultGroup(optargs_)) {
writer.format("%noptional arguments:%n");
printArgumentHelp(writer, optargs_, formatWidth);
}
if (subparsers_.hasSubCommand() && !subparsersUntitled) {
writer.format("%n%s:%n",
subparsers_.getTitle().isEmpty() ? "subcommands"
: subparsers_.getTitle());
if (!subparsers_.getDescription().isEmpty()) {
writer.format(" %s%n%n", TextHelper.wrap(textWidthCounter_,
subparsers_.getDescription(), formatWidth, 2, "", " "));
}
subparsers_.printSubparserHelp(writer, formatWidth);
}
for (ArgumentGroupImpl group : arggroups_) {
if (group.isSeparateHelp()) {
writer.println();
group.printHelp(writer, formatWidth);
}
}
if (!epilog_.isEmpty()) {
writer.format("%n%s%n", TextHelper.wrap(textWidthCounter_, epilog_,
formatWidth, 0, "", ""));
}
writer.flush();
}
private boolean checkDefaultGroup(List args) {
if (args.isEmpty()) {
return false;
}
for (ArgumentImpl arg : args) {
if (arg.getArgumentGroup() == null
|| !arg.getArgumentGroup().isSeparateHelp()) {
return true;
}
}
return false;
}
@Override
public String formatHelp() {
StringWriter writer = new StringWriter();
printHelp(new PrintWriter(writer));
return writer.toString();
}
private void printArgumentUsage(PrintWriter writer, List opts,
int offset, String firstIndent, String subsequentIndent,
int format_width) {
int currentWidth = offset + firstIndent.length();
writer.print(firstIndent);
boolean first = true;
for (String syntax : opts) {
if (!first && currentWidth + syntax.length() + 1 > format_width) {
writer.println();
writer.print(subsequentIndent);
writer.print(" ");
writer.print(syntax);
currentWidth = subsequentIndent.length() + 1 + syntax.length();
} else {
writer.print(" ");
writer.print(syntax);
currentWidth += 1 + syntax.length();
first = false;
}
}
writer.println();
}
@Override
public void printUsage() {
printUsage(new PrintWriter(System.out));
}
@Override
public void printUsage(PrintWriter writer) {
printUsage(writer, ArgumentParsers.getFormatWidth());
}
private void printUsage(PrintWriter writer, int format_width) {
if (!usage_.isEmpty()) {
writer.format("usage: %s%n", substitutePlaceholder(usage_));
return;
}
String usageprog = String.format("usage: %s", prog_);
writer.print(usageprog);
int offset;
String firstIndent;
String subsequentIndent;
String indent = " ";
int usageprogWidth = textWidthCounter_.width(usageprog);
if (usageprogWidth > indent.length()) {
writer.println();
offset = 6;
firstIndent = subsequentIndent = indent.substring(0, offset);
} else {
offset = usageprogWidth;
firstIndent = "";
subsequentIndent = indent.substring(0, offset);
}
List opts = new ArrayList();
addUpperParserUsage(opts, mainParser_);
if (command_ != null) {
opts.add(command_);
}
for (ArgumentImpl arg : optargs_) {
if (arg.getHelpControl() != Arguments.SUPPRESS
&& (arg.getArgumentGroup() == null || !arg
.getArgumentGroup().isMutex())) {
opts.add(arg.formatShortSyntax());
}
}
for (ArgumentGroupImpl group : arggroups_) {
List args = filterSuppressedArgs(group.getArgs());
int numArgs = args.size();
if (group.isMutex()) {
if (numArgs > 1) {
opts.add((group.isRequired() ? "(" : "[")
+ args.get(0).formatShortSyntaxNoBracket());
for (int i = 1; i < numArgs - 1; ++i) {
ArgumentImpl arg = args.get(i);
opts.add("|");
opts.add(arg.formatShortSyntaxNoBracket());
}
opts.add("|");
opts.add(args.get(numArgs - 1).formatShortSyntaxNoBracket()
+ (group.isRequired() ? ")" : "]"));
} else if (numArgs == 1) {
if (group.isRequired()) {
opts.add(args.get(0).formatShortSyntaxNoBracket());
} else {
opts.add(args.get(0).formatShortSyntax());
}
}
}
}
for (ArgumentImpl arg : posargs_) {
if (arg.getHelpControl() != Arguments.SUPPRESS) {
opts.add(arg.formatShortSyntax());
}
}
if (subparsers_.hasSubCommand()) {
opts.add(subparsers_.formatShortSyntax());
opts.add("...");
}
printArgumentUsage(writer, opts, offset, firstIndent, subsequentIndent,
format_width);
}
/**
* Returns arguments in {@code args} whose {@link Argument#getHelpControl()}
* do not return {@link Arguments#SUPPRESS}.
*
* @param args
* @return filtered list of arguments
*/
private static List filterSuppressedArgs(
Collection args) {
ArrayList res = new ArrayList();
for (ArgumentImpl arg : args) {
if (arg.getHelpControl() != Arguments.SUPPRESS) {
res.add(arg);
}
}
return res;
}
/**
* Appends command, required optional arguments and positional arguments in
* {@code parser} to {@code opts} recursively. Most upper parser stores
* first, just like post order traversal.
*
* @param opts
* Command, required optional arguments and positional arguments.
* @param parser
* The parser
*/
private void addUpperParserUsage(List opts,
ArgumentParserImpl parser) {
if (parser == null) {
return;
}
addUpperParserUsage(opts, parser.mainParser_);
if (parser.command_ != null) {
opts.add(parser.command_);
}
for (ArgumentImpl arg : parser.optargs_) {
if (arg.getHelpControl() != Arguments.SUPPRESS
&& arg.isRequired()
&& (arg.getArgumentGroup() == null || !arg
.getArgumentGroup().isMutex())) {
opts.add(arg.formatShortSyntax());
}
}
for (ArgumentGroupImpl group : parser.arggroups_) {
List args = filterSuppressedArgs(group.getArgs());
int numArgs = args.size();
if (group.isMutex()) {
if (numArgs > 1) {
if (group.isRequired()) {
opts.add("(" + args.get(0).formatShortSyntaxNoBracket());
for (int i = 1; i < numArgs - 1; ++i) {
ArgumentImpl arg = args.get(i);
opts.add("|");
opts.add(arg.formatShortSyntaxNoBracket());
}
opts.add("|");
opts.add(args.get(numArgs - 1)
.formatShortSyntaxNoBracket() + ")");
}
} else if (numArgs == 1) {
if (group.isRequired()) {
opts.add(args.get(0).formatShortSyntaxNoBracket());
} else if (args.get(0).isRequired()) {
opts.add(args.get(0).formatShortSyntax());
}
}
}
}
for (ArgumentImpl arg : parser.posargs_) {
if (arg.getHelpControl() != Arguments.SUPPRESS) {
opts.add(arg.formatShortSyntax());
}
}
}
@Override
public String formatUsage() {
StringWriter writer = new StringWriter();
printUsage(new PrintWriter(writer));
return writer.toString();
}
@Override
public ArgumentParserImpl setDefault(String dest, Object value) {
defaults_.put(dest, value);
return this;
}
@Override
public ArgumentParserImpl setDefaults(Map attrs) {
defaults_.putAll(attrs);
return this;
}
/**
* Returns default value set by {@link ArgumentImpl#setDefault(Object)} or
* {@link ArgumentParserImpl#setDefault(String, Object)}. Please note that
* while parser-level defaults always override argument-level defaults while
* parsing, this method examines argument-level defaults first. If no
* default value is found, then check parser-level defaults.
*
* @param dest
* attribute name of default value to get.
* @return default value of given dest.
*/
@Override
public Object getDefault(String dest) {
for (ArgumentImpl arg : optargs_) {
if (dest.equals(arg.getDest()) && arg.getDefault() != null) {
return arg.getDefault();
}
}
for (ArgumentImpl arg : posargs_) {
if (dest.equals(arg.getDest()) && arg.getDefault() != null) {
return arg.getDefault();
}
}
return defaults_.get(dest);
}
@Override
public Namespace parseArgsOrFail(String args[]) {
try {
Namespace ns = parseArgs(args);
return ns;
} catch (ArgumentParserException e) {
handleError(e);
System.exit(1);
}
return null;
}
@Override
public Namespace parseArgs(String args[]) throws ArgumentParserException {
Map attrs = new HashMap();
parseArgs(args, attrs);
return new Namespace(attrs);
}
@Override
public void parseArgs(String[] args, Map attrs)
throws ArgumentParserException {
parseArgs(args, 0, attrs);
}
@Override
public void parseArgs(String[] args, Object userData)
throws ArgumentParserException {
Map opts = new HashMap();
parseArgs(args, opts, userData);
}
@Override
public void parseArgs(String[] args, Map attrs,
Object userData) throws ArgumentParserException {
parseArgs(args, 0, attrs);
Class userClass = userData.getClass();
while (userClass != null) {
for (final Field field : userClass.getDeclaredFields()) {
Arg ann = field.getAnnotation(Arg.class);
if (ann != null) {
String argDest = ann.dest();
if (argDest.isEmpty()) {
argDest = field.getName();
}
if (!attrs.containsKey(argDest)) {
continue;
}
Object val = attrs.get(argDest);
try {
AccessController
.doPrivileged(new PrivilegedAction() {
@Override
public Void run() {
field.setAccessible(true);
return null;
}
});
field.set(userData,
ReflectHelper.list2Array(field.getType(), val));
} catch (RuntimeException e) {
if (!ann.ignoreError()) {
throw e;
}
} catch (Exception e) {
if (!ann.ignoreError()) {
throw new IllegalArgumentException(String.format(
"Could not set %s to field %s", val,
field.getName()), e);
}
}
}
}
for (final Method method : userClass.getDeclaredMethods()) {
Arg ann = method.getAnnotation(Arg.class);
if (ann != null) {
String argDest = ann.dest();
if (argDest.isEmpty()) {
argDest = method.getName();
}
if (!attrs.containsKey(argDest)) {
continue;
}
Object val = attrs.get(argDest);
Class>[] fargs = method.getParameterTypes();
if (fargs.length != 1) {
throw new IllegalArgumentException(String.format(
"Method %s must have one formal parameter",
method.getName()));
}
try {
AccessController
.doPrivileged(new PrivilegedAction() {
@Override
public Void run() {
method.setAccessible(true);
return null;
}
});
method.invoke(userData,
ReflectHelper.list2Array(fargs[0], val));
} catch (RuntimeException e) {
if (!ann.ignoreError()) {
throw e;
}
} catch (Exception e) {
if (!ann.ignoreError()) {
throw new IllegalArgumentException(String.format(
"Could not call method %s with %s",
method.getName(), val), e);
}
}
}
}
userClass = userClass.getSuperclass();
}
}
public void parseArgs(String args[], int offset, Map attrs)
throws ArgumentParserException {
ParseState state = new ParseState(args, offset, negNumFlag_);
parseArgs(state, attrs);
}
/**
* Check that term forms a valid concatenated short options. Note that this
* option does not actually process arguments. Therefore, true from this
* function does not mean all arguments in term are acceptable.
*
* @param term
* string to inspect
* @return true if term forms a valid concatenated short options.
*/
private boolean checkConcatenatedShortOpts(String term) {
if (SHORT_OPTS_PATTERN.matcher(term).matches()) {
for (int i = 1, termlen = term.length(); i < termlen; ++i) {
String shortFlag = "-" + term.charAt(i);
ArgumentImpl arg = optargIndex_.get(shortFlag);
if (arg == null) {
return false;
}
if (arg.getAction().consumeArgument()) {
return true;
}
}
return true;
} else {
return false;
}
}
/**
* Returns optional argument ArgumentImpl which matches given flag. This
* function handles abbreviation as well. If flag is ambiguous,
* {@link ArgumentParserException} will be thrown. If flag does not match
* nay ArgumentImpl, this function returns null.
*
* @param flag
* flag to match
* @return ArgumentImpl which matches flag if it succeeds, or null
* @throws ArgumentParserException
* if flag is ambiguous
*/
private ArgumentImpl resolveNextFlag(String flag)
throws ArgumentParserException {
ArgumentImpl arg = optargIndex_.get(flag);
if (arg != null) {
return arg;
}
List cand = TextHelper.findPrefix(optargIndex_.keySet(), flag);
if (cand.isEmpty()) {
return null;
} else if (checkConcatenatedShortOpts(flag)) {
// Get first short option
cand.add(flag.substring(0, 2));
} else if (cand.size() == 1) {
return optargIndex_.get(cand.get(0));
}
// At this point, more than 1 flags were found from optargIndex_
// and/or flag forms concatenated short options.
// Sort in order to make unit test easier.
Collections.sort(cand);
throw new ArgumentParserException(String.format(
"ambiguous option: %s could match %s", flag,
TextHelper.concat(cand, 0, ", ")), this);
}
public void parseArgs(ParseState state, Map attrs)
throws ArgumentParserException {
populateDefaults(attrs);
Set used = new HashSet();
ArgumentImpl[] groupUsed = new ArgumentImpl[arggroups_.size()];
int posargIndex = 0;
int posargsLen = posargs_.size();
while (state.isArgAvail()) {
// We first evaluate flagFound(state) before comparing arg to "--"
// in order to expand arguments from file.
if (flagFound(state) && !"--".equals(state.getArg())) {
String term = state.getArg();
int p = term.indexOf("=");
String flag;
String embeddedValue;
if (p == -1) {
flag = term;
embeddedValue = null;
} else {
flag = term.substring(0, p);
embeddedValue = term.substring(p + 1);
}
ArgumentImpl arg = resolveNextFlag(flag);
if (arg == null) {
// Assign null for clarity
embeddedValue = null;
boolean shortOptsFound = false;
if (SHORT_OPTS_PATTERN.matcher(term).matches()) {
shortOptsFound = true;
// Possible concatenated short options
for (int i = 1, termlen = term.length(); i < termlen; ++i) {
String shortFlag = "-" + term.charAt(i);
arg = optargIndex_.get(shortFlag);
if (arg == null) {
shortOptsFound = false;
break;
}
if (arg.getAction().consumeArgument()) {
flag = shortFlag;
shortOptsFound = true;
if (term.length() > i + 1) {
embeddedValue = term.substring(i + 1);
}
break;
}
checkMutex(arg, groupUsed);
arg.run(this, attrs, shortFlag, null);
used.add(arg);
// Set null to avoid using it twice.
arg = null;
}
}
if (!shortOptsFound) {
throw new UnrecognizedArgumentException(
formatUnrecognizedArgumentErrorMessage(state,
term), this, term);
}
}
++state.index;
if (arg != null) {
checkMutex(arg, groupUsed);
processArg(attrs, state, arg, flag, embeddedValue);
used.add(arg);
}
} else if ("--".equals(state.getArg()) && !state.consumedSeparator) {
state.consumedSeparator = true;
state.negNumFlag = false;
++state.index;
} else if (posargIndex < posargsLen) {
ArgumentImpl arg = posargs_.get(posargIndex++);
processArg(attrs, state, arg, null, null);
} else if (!state.consumedSeparator && subparsers_.hasSubCommand()) {
checkRequiredArgument(used, posargIndex);
checkRequiredMutex(groupUsed);
subparsers_.parseArg(state, attrs);
return;
} else {
throw new ArgumentParserException(
formatUnrecognizedArgumentErrorMessage(state,
TextHelper.concat(state.args, state.index, " ")),
this);
}
}
if (subparsers_.hasSubCommand()) {
throw new ArgumentParserException("too few arguments", this);
}
while (posargIndex < posargsLen) {
ArgumentImpl arg = posargs_.get(posargIndex++);
processArg(attrs, state, arg, null, null);
}
checkRequiredArgument(used, posargIndex);
checkRequiredMutex(groupUsed);
}
/**
* Format message for "Unrecognized arguments" error.
*
* @param state
* Current parser state
* @param args
* Textual representation of unrecognized arguments to be
* included in the message as is.
* @return formatted error message
*/
private String formatUnrecognizedArgumentErrorMessage(ParseState state,
String args) {
return String
.format("unrecognized arguments: '%s'%s",
args,
state.index > state.lastFromFileArgIndex ? ""
: String.format(
"%nChecking trailing white spaces or new lines in %sfile may help.",
fromFilePrefixPattern_.getPrefixChars()
.length() == 1 ? fromFilePrefixPattern_
.getPrefixChars() : "["
+ fromFilePrefixPattern_
.getPrefixChars() + "]"));
}
/**
* Check that another option in mutually exclusive group has already been
* specified. If so, throw an exception.
*
* @param arg
* The argument currently processed
* @param groupUsed
* The cache of used argument in each groups.
* @throws ArgumentParserException
* If another option in mutually exclusive group has already
* been used.
*/
private void checkMutex(ArgumentImpl arg, ArgumentImpl[] groupUsed)
throws ArgumentParserException {
if (arg.getArgumentGroup() != null) {
if (arg.getArgumentGroup().isMutex()) {
ArgumentImpl usedMutexArg = groupUsed[arg.getArgumentGroup()
.getIndex()];
if (usedMutexArg == null) {
groupUsed[arg.getArgumentGroup().getIndex()] = arg;
} else if (usedMutexArg != arg) {
throw new ArgumentParserException(String.format(
"not allowed with argument %s",
usedMutexArg.textualName()), this, arg);
}
}
}
}
/**
* @param res
* @param state
* state.offset points to the argument next to flag
* @param arg
* @param flag
* @param embeddedValue
* If optional argument is given as "foo=bar" or "-fbar" (short
* option), embedded value is "bar". Otherwise {@code null}
* @throws ArgumentParserException
*/
private void processArg(Map res, ParseState state,
ArgumentImpl arg, String flag, String embeddedValue)
throws ArgumentParserException {
if (!arg.getAction().consumeArgument()) {
if (embeddedValue == null) {
arg.run(this, res, flag, null);
return;
} else {
throw new ArgumentParserException(String.format(
"ignore implicit argument '%s'", embeddedValue), this,
arg);
}
}
if (arg.getMinNumArg() == -1
|| (arg.getMinNumArg() == 0 && arg.getMaxNumArg() == 1)) {
// In case of: option takes exactly one argument, or nargs("?")
String argval = null;
if (embeddedValue == null) {
if (state.isArgAvail() && !flagFound(state)) {
argval = state.getArg();
++state.index;
}
} else {
argval = embeddedValue;
}
if (argval == null) {
if (arg.getMinNumArg() == -1) {
if (arg.isOptionalArgument()) {
throw new ArgumentParserException(
"expected one argument", this, arg);
} else {
throw new ArgumentParserException("too few arguments",
this);
}
} else if (arg.isOptionalArgument()) {
// This is a special treatment for nargs("?"). If flag is
// given but no argument follows, produce const value.
arg.run(this, res, flag, arg.getConst());
}
} else {
arg.run(this, res, flag, arg.convert(this, argval));
}
} else {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy