org.jenkinsci.plugins.tokenmacro.Tokenizer Maven / Gradle / Ivy
The newest version!
/*
* The MIT License
*
* Copyright 2009- Kyle Sweeney, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.tokenmacro;
import com.google.common.base.Supplier;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parses strings with macro references.
*
* @author [email protected]
* @author Kohsuke Kawaguchi
*/
class Tokenizer {
private static final String tokenNameRegex = "[a-zA-Z_][a-zA-Z0-9_]*";
private static final String numberRegex = "-?[0-9]+(\\.[0-9]*)?";
private static final String boolRegex = "(true)|(false)";
// Sequence of (1) not \ " CR LF and (2) \ followed by (CR)LF, or not CR LF
// Use possessive quantifier to prevent stack overflow (see HUDSON-14132)
private static final String stringRegex = "\"([^\\\\\"\\r\\n]|(\\\\(?:\r?\n|.)))*+\"";
private static final String valueRegex = "(" + numberRegex + ")|(" + boolRegex + ")|(" + stringRegex + ")";
private static final String spaceRegex = "[ \\t]*";
private static final String argRegex = "(" + tokenNameRegex + ")" + spaceRegex + "=" + spaceRegex + "(" + valueRegex + ")";
private static final String argsRegex = "((" + spaceRegex + "," + spaceRegex + argRegex + ")*)";
private static final String delimitedTokenRegex = "\\{" + spaceRegex + "(" + tokenNameRegex + ")" + argsRegex + spaceRegex + "\\}";
private static final String tokenRegex = "(\\$?)\\$((" + tokenNameRegex + ")|(" + delimitedTokenRegex + "))";
private static final Pattern argPattern = Pattern.compile(argRegex);
private static final Pattern tokenPattern = Pattern.compile(tokenRegex);
private static final String ESCAPE_STRING = "$$";
private final Matcher tokenMatcher;
private String tokenName = null;
private ListMultimap args = null;
Tokenizer(String origText) {
tokenMatcher = tokenPattern.matcher(origText);
}
String getTokenName() {
return tokenName;
}
ListMultimap getArgs() {
return args;
}
String group() {
return tokenMatcher.group();
}
boolean isEscaped() {
return tokenMatcher.group().startsWith(ESCAPE_STRING);
}
boolean find() {
if (tokenMatcher.find()) {
if(isEscaped()) {
return true;
}
tokenName = tokenMatcher.group(3);
if (tokenName == null) {
tokenName = tokenMatcher.group(5);
}
args = Multimaps.newListMultimap(new TreeMap>(),new Supplier>() {
public List get() {
return new ArrayList();
}
});
if (tokenMatcher.group(6) != null) {
parseArgs(tokenMatcher.group(6), args);
}
return true;
} else {
return false;
}
}
static void parseArgs(String argsString, ListMultimap args) {
Matcher argMatcher = argPattern.matcher(argsString);
while (argMatcher.find()) {
String arg;
if (argMatcher.group(3) != null) {
// number
arg = argMatcher.group(3);
// if (argMatcher.group(4) != null) {
// arg = Float.valueOf();
// } else {
// arg = Integer.valueOf(argMatcher.group(3));
// }
} else if (argMatcher.group(5) != null) {
// boolean
if (argMatcher.group(6) != null) {
// arg = Boolean.TRUE;
arg = "true";
} else {
// arg = Boolean.FALSE;
arg = "false";
}
} else { // if (argMatcher.group(8) != null) {
// string
arg = unescapeString(argMatcher.group(8));
}
args.put(argMatcher.group(1), arg);
}
}
void appendReplacement(StringBuffer sb, String replacement) {
tokenMatcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
}
void appendTail(StringBuffer sb) {
tokenMatcher.appendTail(sb);
}
/**
* Replaces all the printf-style escape sequences in a string
* with the appropriate characters.
*
* @param escapedString the string containing escapes
* @return the string with all the escape sequences replaced
*/
public static String unescapeString(String escapedString) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i < escapedString.length() - 1; ++i) {
char c = escapedString.charAt(i);
if (c == '\\') {
++i;
sb.append(unescapeChar(escapedString.charAt(i)));
} else {
sb.append(c);
}
}
return sb.toString();
}
private static char unescapeChar(char escapedChar) {
switch (escapedChar) {
case 'b':
return '\b';
case 't':
return '\t';
case 'n':
return '\n';
case 'f':
return '\f';
case 'r':
return '\r';
default:
return escapedChar;
}
}
}