com.obdobion.argument.input.CommandLineParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of argument Show documentation
Show all versions of argument Show documentation
A command line parser for Java
package com.obdobion.argument.input;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.obdobion.argument.type.ICmdLineArg;
/**
* This parser takes a typical command line entry and creates tokens. A command
* line is made up of key words and values. A key word is prefixed by a - or
* two. Brackets or parenthesis may be used to create subparsers.
*
* @author Chris DeGreef
*
*/
public class CommandLineParser extends AbstractInputParser implements IParserInput
{
static private StringBuilder convertToString(
final File commandFile)
throws FileNotFoundException,
IOException
{
final FileReader fis = new FileReader(commandFile);
try (final BufferedReader buf = new BufferedReader(fis))
{
final StringBuilder str = new StringBuilder();
String input = buf.readLine();
while (input != null)
{
/*
* Allow comments if the first character on a line is #. It must
* be column 1.
*/
if (input.length() > 0 && input.charAt(0) != '#')
{
str.append(input);
str.append(' ');
}
input = buf.readLine();
}
return str;
}
}
static public IParserInput getInstance(
final char commandPrefix,
final boolean allowEmbeddedCommandPrefix,
final File args)
throws IOException
{
final CommandLineParser parser = new CommandLineParser();
parser.commandPrefix = commandPrefix;
parser.allowEmbeddedCommandPrefix = allowEmbeddedCommandPrefix;
parser.commandLine = convertToString(args).toString();
return parser;
}
static public IParserInput getInstance(
final char commandPrefix,
final boolean allowEmbeddedCommandPrefix,
final String... args)
{
final CommandLineParser parser = new CommandLineParser();
parser.commandPrefix = commandPrefix;
parser.allowEmbeddedCommandPrefix = allowEmbeddedCommandPrefix;
final StringBuilder str = new StringBuilder();
for (int c = 0; c < args.length; c++)
{
str.append(args[c].replaceAll("\\\\", "\\\\\\\\"));
str.append(" ");
}
parser.commandLine = str.toString();
return parser;
}
static public IParserInput getInstance(
final char commandPrefix,
final File args)
throws IOException
{
return getInstance(commandPrefix, false, args);
}
static public IParserInput getInstance(
final char commandPrefix,
final String... args)
{
return getInstance(commandPrefix, false, args);
}
static public String unparseTokens(
final List> args)
{
final StringBuilder out = new StringBuilder();
unparseTokens(args, out);
return out.toString();
}
static public void unparseTokens(
final List> args,
final StringBuilder out)
{
final Iterator> aIter = args.iterator();
boolean first = true;
while (aIter.hasNext())
{
final ICmdLineArg> arg = aIter.next();
if (arg.isParsed())
{
if (!first)
out.append(" ");
first = false;
arg.exportCommandLine(out);
}
}
}
protected String commandLine;
char commandPrefix;
boolean allowEmbeddedCommandPrefix;
private CommandLineParser()
{
super();
allowEmbeddedCommandPrefix = true;
}
@Override
public Token[] parseTokens()
{
char delim = ' ';
final StringBuilder part = new StringBuilder();
boolean inToken = false;
int startX = 0;
final List tokens = new ArrayList<>();
char thisChar = ' ';
char prevChar;
for (int scanX = 0; scanX < commandLine.length(); scanX++)
{
prevChar = thisChar;
thisChar = commandLine.charAt(scanX);
if (inToken)
{
if (delim != ' ' && thisChar == delim)
{
tokens.add(new Token(commandPrefix,
part.toString(),
startX,
scanX + 1,
true));
part.delete(0, part.length());
inToken = false;
} else
{
char nextChar = ' ';
/*
* Look ahead one char if possible
*/
if (scanX < commandLine.length() - 2)
nextChar = commandLine.charAt(scanX + 1);
/*
* As long as we are not in a quoted literal then we want to
* split the token if any of these conditions are true.
*/
if (delim == ' '
&& (Character.isWhitespace(thisChar)
|| thisChar == '('
|| thisChar == ')'
|| thisChar == '['
|| thisChar == ']'
|| thisChar == ';'
|| thisChar == ','
|| thisChar == '='
|| thisChar == '"'
|| thisChar == '\''
/*
* Make sure to allow double dashes at the
* beginning of a token, the second one is
* technically not an embedded dash.
*/
|| (!allowEmbeddedCommandPrefix
&& thisChar == commandPrefix
&& prevChar != commandPrefix)
/*
* Even if we are allowing embedded
* tokens we don't want to allow
* double dashes within a token,
* only at the beginning. A double
* dash will indicate that a new
* token should be started instead.
*/
|| (allowEmbeddedCommandPrefix
&& thisChar == commandPrefix
&& nextChar == commandPrefix)
/*
* An embedded dash will cause a new
* token if the current token
* started with a single dash
*/
|| (thisChar == commandPrefix
&& part.length() > 1
&& part.charAt(0) == commandPrefix
&& part.charAt(1) != commandPrefix)))
{
boolean forceLiteral = false;
/*
* Single char commands can not be a number. This allows
* negative numbers to be entered without escaping them
* or surrounding them with delimiters.
*/
if (part.length() > 1)
if (part.charAt(0) == commandPrefix
&& Character.isDigit(part.charAt(1)))
forceLiteral = true;
tokens.add(new Token(commandPrefix,
part.toString(),
startX,
scanX,
forceLiteral));
part.delete(0, part.length());
/*
* rescan char
*/
--scanX;
inToken = false;
} else
{
if (thisChar == '\\')
thisChar = commandLine.charAt(++scanX);
part.append(thisChar);
}
}
} else
{
/*
* Completely throw away whitespace characters unless quoted.
* They served their purpose in that they caused a token to be
* stopped.
*/
if (Character.isWhitespace(thisChar)
|| thisChar == ':'
|| thisChar == ';'
|| thisChar == ','
|| thisChar == '=')
continue;
if (thisChar == '(' || thisChar == ')' || thisChar == '[' || thisChar == ']')
{
tokens.add(new Token(commandPrefix,
"" + thisChar,
scanX,
scanX + 1,
false));
continue;
}
if (thisChar == '"' || thisChar == '\'')
delim = thisChar;
else
{
delim = ' ';
part.append(thisChar);
}
inToken = true;
startX = scanX;
}
}
if (inToken)
tokens.add(new Token(commandPrefix,
part.toString(),
startX,
commandLine.length(),
delim != ' '));
return tokens.toArray(new Token[tokens.size()]);
}
@Override
public String substring(final int inclusiveStart, final int exclusiveEnd)
{
return commandLine.substring(inclusiveStart, exclusiveEnd);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy