/**
* VMware Continuent Tungsten Replicator
* Copyright (C) 2015 VMware, Inc. 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.
*
* Initial developer(s): Ed Archibald
* Contributor(s): Linas Virbalas, Gilles Rayrat
*/
package com.continuent.tungsten.common.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Vector;
import jline.ConsoleReader;
public class CommandLineParser
{
private static final String FLAG_INTRODUCER = "-";
private static final char LONG_FLAG = 'l';
private static final char RECURSIVE_FLAG = 'R';
public static final char ABSOLUTE_FLAG = 'A';
public static final char PARENTS_FLAG = 'p';
public static final char BACKGROUND_FLAG = '&';
private static final String BACKGROUND_TOKEN = "&";
private static final String REDIRECT_OUT_TOKEN = ">";
private static final String REDIRECT_IN_TOKEN = "<";
public static void main(String[] args)
{
try
{
ConsoleReader reader = new ConsoleReader();
CommandLineParser parser = new CommandLineParser();
Vector<Command> cmds = null;
while ((cmds = parser.getCommand(reader, "> ", null, true)) != null)
{
for (Command cmd : cmds)
{
System.out.println(CLUtils.printArgs(cmd.getTokens()));
System.out.println(cmd.isBackground()
? "BACKGROUND"
: "FOREGROUND");
System.out.println(cmd.isLong() ? "LONG" : "SHORT");
System.out
.println(cmd.isRecursive() ? "RECURSIVE" : "FLAT");
System.out.println(cmd.isRedirectInput() ? "INPUT="
+ cmd.getInput() : "STDIN");
System.out.println(cmd.isRedirectOutput() ? "OUTPUT="
+ cmd.getOutput() : "STDOUT");
}
}
}
catch (IOException e)
{
System.out.println(e);
}
}
public Command parseOne(String commandLine, boolean parseFlags)
{
Vector<Command> cmds = parse(commandLine, parseFlags);
if (cmds.size() == 1)
{
return cmds.get(0);
}
else if (cmds.size() > 1)
{
CLUtils.println("Multiple commands, separated by ';' are not allowed here.");
}
return null;
}
public Command parseOne(String commandLine)
{
return parseOne(commandLine, true);
}
public Vector<Command> parse(String commandLine)
{
return parse(commandLine, true);
}
/**
* This method parses a set of tokens returned by a simple command line
* parser, strips out any 'meta' commands and sets the appropriate flags,
* and returns the 'clean' set of tokens to be processed by the command
* processor.
*/
public Vector<Command> parse(String commandBuf, boolean parseFlags)
{
Vector<Command> commandList = new Vector<Command>();
String[] commands = commandBuf.split(";");
for (String commandLine : commands)
{
Command command = new Command(commandLine);
String splitPattern = null;
if (parseFlags)
{
splitPattern = "\\s+|\\s+-\\b|'|\"";
}
else
{
splitPattern = "\\s+|'|\"";
}
// First strip blanks
Vector<String> noBlanks = new Vector<String>();
noBlanks.toArray(new String[noBlanks.size()]);
String[] tokens = commandLine.split(splitPattern);
for (String token : tokens)
{
if (!token.trim().equals(""))
noBlanks.add(token.trim());
}
// If there are no non-blank tokens, just return null;
if (noBlanks.size() == 0)
{
return null;
}
// Now evaluate the tokens and set appropriate flags,
// stripping out any tokens that are flag-specific
int i = 0;
while (true)
{
if (i == noBlanks.size())
break;
String currentToken = noBlanks.get(i);
if (parseFlags
&& currentToken.trim().startsWith(FLAG_INTRODUCER))
{
char[] flagChars = currentToken.trim().toCharArray();
for (int j = 1; j < flagChars.length; j++)
{
char flagChar = flagChars[j];
if (flagChar == LONG_FLAG)
command.setIsLong(true);
else if (flagChar == RECURSIVE_FLAG)
command.setIsRecursive(true);
else if (flagChar == PARENTS_FLAG)
command.setIncludeParents(true);
else if (flagChar == ABSOLUTE_FLAG)
command.setIsAbsolute(true);
else if (flagChar == BACKGROUND_FLAG)
{
if (i + 1 == noBlanks.size()
&& (j + 1 == flagChars.length))
{
command.setIsBackground(true);
}
else
CLUtils.println("The token '&' can only appear at the end of a command");
}
}
}
else if (currentToken.trim().equals(REDIRECT_IN_TOKEN))
{
if (i + 1 < noBlanks.size())
{
String input = noBlanks.get(++i);
command.setIsRedirectInput(true, input);
}
else
{
CLUtils.println("No arg supplied for input redirection");
}
}
else if (currentToken.trim().equals(REDIRECT_OUT_TOKEN))
{
if (i + 1 < noBlanks.size())
{
String output = noBlanks.get(++i);
command.setIsRedirectOutput(true, output);
}
else
{
CLUtils.println("No arg supplied for output redirection");
}
}
else if (currentToken.trim().endsWith(BACKGROUND_TOKEN))
{
if (i + 1 == noBlanks.size())
{
command.setIsBackground(true);
if (currentToken.trim().length() > 1)
{
currentToken = currentToken.trim().substring(0,
currentToken.indexOf(BACKGROUND_TOKEN));
command.addToken(currentToken);
}
}
else
CLUtils.println("The token '&' can only appear at the end of a command");
}
else
{
command.addToken(currentToken);
}
i++;
}
if (command.getTokens() != null)
{
commandList.add(command);
}
}
return commandList;
}
public Vector<Command> getCommand(ConsoleReader cr, String prompt,
BufferedReader in) throws IOException
{
return getCommand(cr, prompt, in, true);
}
public Vector<Command> getCommand(ConsoleReader cr, String prompt,
BufferedReader in, boolean printPrompt) throws IOException
{
String inbuf = null;
if (cr != null)
{
if (printPrompt)
inbuf = cr.readLine(prompt);
else
inbuf = cr.readLine("");
}
else
{
if (printPrompt)
System.out.print(prompt);
CLUtils.println("Using in.readline()");
inbuf = in.readLine();
}
if (inbuf == null)
{
CLUtils.println("\nExiting...");
System.exit(0);
}
return parse(inbuf, true);
}
}