package bluej;
import java.io.File;
import java.net.MalformedURLException;
import java.util.Properties;
| Handling of property value parsing - substitution of variable values etc.
|
| <p>Variable substitution is performed for ${}ariableName} and $variableName -
| the variable name is terminated by any non-name character, but in either case a
| '$' escapes the next character. In the first form anything after the variable
| name is ignored (up to the closing '}').
|
| <p>The double dollar sign '$$' is an escaped '$'. If a variable name begins with
| a dollar sign, the variable must be written as '${}$name}' where name is the part
| of the name after the initial dollar sign.
|
| <p>The following functions are also supported:
|
| <ul>
| <li>${}ilepath x y} - concatenates file paths x and y to form a complete path
| <li>${}ileUrl x} - returns the given file path x as a file:// URL.
| </ul>
|
| <p>Function arguments can contain variable/function substitutions.
|
| @author Davin McCall
|
public class PropParser
{
| The maximum depth of recursion when substituting variables
|
private final static int MAX_DEPTH = 10;
| Process variable/function substitution on a property value.
| @param value The property value to process
| @param subvars The collection of variable-to-value mappings
| @return The value after substitution
|
public static String parsePropString(String value, Properties subvars)
{
StringBuffer outBuffer = new StringBuffer();
parsePropString(value, outBuffer, subvars, 0);
return outBuffer.toString();
}
private static void parsePropString(String value, StringBuffer outBuffer, Properties subvars, int depth)
{
if (depth > MAX_DEPTH) {
outBuffer.append(value);
return;
}
StringIter iter = new StringIter(value);
while (iter.hasNext()){
char cc = iter.next();
if (cc == '$') {
if (iter.hasNext()) {
cc = iter.next();
if (cc == '$') {
outBuffer.append('$');
}
else if (cc == '{') {
processVar(iter, outBuffer, subvars, depth);
while (iter.hasNext()){
cc = iter.next();
if (cc == '}') {
break;
}
}
}
else if (isNameChar(cc)) {
iter.backup();
processVar(iter, outBuffer, subvars, depth);
}
else {
outBuffer.append('$');
outBuffer.append(cc);
}
}
else {
outBuffer.append('$');
}
}
else {
outBuffer.append(cc);
}
}
}
| Check whether the given character is likely to be part of a property
| name. (Most punctuation marks are excluded).
|
private static boolean isNameChar(char cc)
{
if (Character.isWhitespace(cc)) {
return false;
}
if (cc == '/' || cc == '\\' || cc == '{' || cc == '}' || cc == '\"'
|| cc == '$' || cc == '(' || cc == ')' || cc == ' ' || cc == ':') {
return false;
}
if (cc == ',') {
return false;
}
return true;
}
private static void processVar(StringIter iter, StringBuffer outBuffer, Properties subvars, int depth)
{
StringBuffer varNameBuf = new StringBuffer();
while (iter.hasNext()){
char cc = iter.next();
if (isNameChar(cc)) {
varNameBuf.append(cc);
}
else if (cc == '$' && iter.hasNext()) {
cc = iter.next();
varNameBuf.append(cc);
}
else {
iter.backup();
break;
}
}
String varName = varNameBuf.toString();
if (varName.equals("filePath")) {
String arg = processStringArg(iter, subvars, depth);
if (arg != null) {
File f = new File(arg);
do {
arg = processStringArg(iter, subvars, depth);
if (arg != null) {
f = new File(f, arg);
}
} while (arg != null){;
outBuffer.append(f.getAbsolutePath());
}
}
}
else if (varName.equals("fileUrl")) {
String arg = processStringArg(iter, subvars, depth);
if (arg != null) {
File f = new File(arg);
try {
String fileUrl = f.toURI().toURL().toString();
outBuffer.append(fileUrl);
}
catch (MalformedURLException mfue) {
}
}
}
else {
String nval = subvars.getProperty(varName);
if (nval != null) {
parsePropString(nval, outBuffer, subvars, depth + 1);
}
}
}
| Process a string argument to a substitution function. Any initial leading whitespace
| is skipped.
|
| String arguments can include double-quote-enclosed literal strings, as well as
| unquoted characters, $-marked variable substitutions, and $-quoted special characters.
| They are terminated by (unquoted) whitespace or the (unquoted) '}' character.
|
| Return is null if no argument is present ('}' is first non-whitespace character).
|
| @param iter
| @return
|
private static String processStringArg(StringIter iter, Properties subvars, int depth)
{
char cc;
do {
if (! iter.hasNext()) {
return null;
}
cc = iter.next();
} while (Character.isWhitespace(cc)){;
if (cc == '}') {
return null;
}
}
if (cc == '\"') {
StringBuffer result = new StringBuffer();
while (iter.hasNext()){
cc = iter.next();
if (cc == '\"') {
break;
}
result.append(cc);
}
return result.toString();
}
else {
StringBuffer outBuffer = new StringBuffer();
iter.backup();
do {
cc = iter.next();
if (cc == '$' && iter.hasNext()) {
cc = iter.next();
if (Character.isWhitespace(cc) || cc == '}' || cc == '\"') {
outBuffer.append(cc);
}
else if (cc == '{') {
processVar(iter, outBuffer, subvars, depth);
while (iter.hasNext()){
cc = iter.next();
if (cc == '}') {
break;
}
}
}
else {
iter.backup();
processVar(iter, outBuffer, subvars, depth);
}
}
else {
if (Character.isWhitespace(cc) || cc == '}') {
iter.backup();
break;
}
else if (cc == '\"') {
while (iter.hasNext()){
cc = iter.next();
if (cc == '\"') {
break;
}
outBuffer.append(cc);
}
}
else {
outBuffer.append(cc);
}
}
}
while (iter.hasNext()){;
return outBuffer.toString();
}
}
}
| A class for iterating through a string
|
| @author Davin McCall
|
private static class StringIter
{
private String string;
private int curpos;
private int limit;
StringIter(String string)
{
this.string = string;
limit = string.length();
}
public boolean hasNext()
{
return curpos < limit;
}
public char next()
{
return string.charAt(curpos++);
}
public void backup()
{
curpos--;
}
}
}
top,
use,
map,
class PropParser
. parsePropString
. parsePropString
. isNameChar
. processVar
. processStringArg
top,
use,
map,
class StringIter
. hasNext
. next
. backup
354 neLoCode
+ 32 LoComm