in log4j-core/src/main/java/org/apache/logging/log4j/core/tools/picocli/CommandLine.java [2357:2437]
private void processClusteredShortOptions(
final Collection<Field> required,
final Set<Field> initialized,
final String arg,
final Stack<String> args)
throws Exception {
final String prefix = arg.substring(0, 1);
String cluster = arg.substring(1);
boolean paramAttachedToOption = true;
do {
if (cluster.length() > 0 && singleCharOption2Field.containsKey(cluster.charAt(0))) {
final Field field = singleCharOption2Field.get(cluster.charAt(0));
Range arity = Range.optionArity(field);
final String argDescription = "option " + prefix + cluster.charAt(0);
if (tracer.isDebug()) {
tracer.debug(
"Found option '%s%s' in %s: field %s, arity=%s%n",
prefix, cluster.charAt(0), arg, field, arity);
}
required.remove(field);
cluster = cluster.length() > 0 ? cluster.substring(1) : "";
paramAttachedToOption = cluster.length() > 0;
if (cluster.startsWith(separator)) { // attached with separator, like -f=FILE or -v=true
cluster = cluster.substring(separator.length());
arity = arity.min(Math.max(1, arity.min)); // if key=value, minimum arity is at least 1
}
if (arity.min > 0 && !empty(cluster)) {
if (tracer.isDebug()) {
tracer.debug("Trying to process '%s' as option parameter%n", cluster);
}
}
// arity may be >= 1, or
// arity <= 0 && !cluster.startsWith(separator)
// e.g., boolean @Option("-v", arity=0, varargs=true); arg "-rvTRUE", remainder cluster="TRUE"
if (!empty(cluster)) {
args.push(cluster); // interpret remainder as option parameter
}
final int consumed = applyOption(
field, Option.class, arity, paramAttachedToOption, args, initialized, argDescription);
// only return if cluster (and maybe more) was consumed, otherwise continue do-while loop
if (empty(cluster) || consumed > 0 || args.isEmpty()) {
return;
}
cluster = args.pop();
} else { // cluster is empty || cluster.charAt(0) is not a short option key
if (cluster.length() == 0) { // we finished parsing a group of short options like -rxv
return; // return normally and parse the next arg
}
// We get here when the remainder of the cluster group is neither an option,
// nor a parameter that the last option could consume.
if (arg.endsWith(cluster)) {
args.push(paramAttachedToOption ? prefix + cluster : cluster);
if (args.peek().equals(arg)) { // #149 be consistent between unmatched short and long options
if (tracer.isDebug()) {
tracer.debug(
"Could not match any short options in %s, deciding whether to treat as unmatched option or positional parameter...%n",
arg);
}
if (resemblesOption(arg)) {
handleUnmatchedArguments(args.pop());
return;
} // #149
processPositionalParameter(required, initialized, args);
return;
}
// remainder was part of a clustered group that could not be completely parsed
if (tracer.isDebug()) {
tracer.debug("No option found for %s in %s%n", cluster, arg);
}
handleUnmatchedArguments(args.pop());
} else {
args.push(cluster);
if (tracer.isDebug()) {
tracer.debug("%s is not an option parameter for %s%n", cluster, arg);
}
processPositionalParameter(required, initialized, args);
}
return;
}
} while (true);
}