/*******************************************************************************
* Copyright (c) 2004, 2006
* Thomas Hallgren, Kenneth Olwing, Mitch Sonies
* Pontus Rydin, Nils Unden, Peer Torngren
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the individual
* copyright holders listed above, as Initial Contributors under such license.
* The text of such license is available at www.eclipse.org.
*******************************************************************************/
package org.eclipse.buckminster.cmdline.parser;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.eclipse.buckminster.runtime.Buckminster;
import org.eclipse.buckminster.runtime.Logger;
/**
* A simple command line parser that implements a subset of the parsing that is
* performed by a normal bourne shell. Environment substitution is performed
* only if the Java runtime is of version 1.5 or higher.
*
* @author Thomas Hallgren
* @see java.util.Iterator
*/
public class CommandLineParser implements Iterator<String> {
private static char getEscapedChar(char escaped) {
switch (escaped) {
case 't':
return '\t';
case 'n':
return '\n';
case 'r':
return '\r';
default:
return escaped;
}
}
private final StringBuffer innerBld = new StringBuffer();
private final StringBuffer outerBld = new StringBuffer();
private final String line;
private String nextToken;
private int pos;
public CommandLineParser(String line) {
this.line = line;
int top = line.length();
while (pos < top) {
char c = line.charAt(pos);
if (Character.isWhitespace(c)) {
++pos;
continue;
}
// Lines where first non-space character is a '#' are considered
// to be comments
//
if (c == '#')
pos = top;
break;
}
}
@Override
public boolean hasNext() {
if (nextToken == null)
nextToken = this.nextToken();
return nextToken != null;
}
@Override
public String next() {
if (!this.hasNext())
throw new NoSuchElementException();
String nxt = nextToken;
nextToken = null;
return nxt;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void getExpanded(StringBuffer bld, String string) {
Logger logger = Buckminster.getLogger();
int top = string.length();
int idx = 0;
while (idx < top) {
char c = string.charAt(idx++);
if (c != '$') {
bld.append(c);
continue;
}
if (idx == top)
break;
int start;
int end;
c = string.charAt(idx);
if (c == '{') {
start = ++idx;
while (idx < top && string.charAt(idx) != '}')
++idx;
end = idx++; // Skip trailing '}'
} else {
start = idx;
while (idx < top && Character.isJavaIdentifierPart(string.charAt(idx)))
++idx;
end = idx;
}
if (end > start) {
String key = string.substring(start, end);
String value = (key.length() > 4 && "env:".equalsIgnoreCase(string.substring(0, 4))) //$NON-NLS-1$
? System.getenv(key.substring(4)) : System.getProperty(key);
logger.debug("key '%s' expanded to '%s'", key, value); //$NON-NLS-1$
if (value != null)
bld.append(value);
}
}
}
private String getQuoted(char quote) {
innerBld.setLength(0);
int top = line.length();
while (pos < top) {
char c = line.charAt(pos++);
if (c == quote)
break;
if (c == '\\') {
if (pos == top)
break;
c = getEscapedChar(line.charAt(pos++));
}
innerBld.append(c);
}
return innerBld.toString();
}
private String getSpaceDelimited() {
innerBld.setLength(0);
int top = line.length();
while (pos < top) {
char c = line.charAt(pos);
if (Character.isWhitespace(c) || c == '\'' || c == '"')
break;
++pos;
if (c == '\\') {
if (pos == top)
break;
// The sequence '\ ' should not cause a break since that
// is an escaped space. The sequence '\t' however, should
// since that is an unescaped tab
//
c = line.charAt(pos++);
if (!Character.isWhitespace(c)) {
c = getEscapedChar(c);
if (Character.isWhitespace(c))
break;
}
}
innerBld.append(c);
}
return innerBld.toString();
}
private String nextToken() {
outerBld.setLength(0);
int top = line.length();
if (pos == top)
return null;
while (pos < top) {
char c = line.charAt(pos);
switch (c) {
case '\'':
// Find matching end quote. No expansion is performed
//
++pos;
outerBld.append(getQuoted('\''));
continue;
case '"':
// Find matching end quote and perform expansion
//
++pos;
getExpanded(outerBld, getQuoted('"'));
continue;
default:
if (Character.isWhitespace(c)) {
++pos;
while (pos < top && Character.isWhitespace(line.charAt(pos)))
++pos;
break;
}
getExpanded(outerBld, getSpaceDelimited());
continue;
}
break;
}
return outerBld.toString();
}
}