package info.bliki.wiki.filter;
import info.bliki.htmlcleaner.Utils;
import info.bliki.wiki.model.Configuration;
import info.bliki.wiki.model.IConfiguration;
import info.bliki.wiki.model.IWikiModel;
import info.bliki.wiki.tags.util.WikiTagNode;
import info.bliki.wiki.template.ITemplateFunction;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* A template parser for the first pass in the parsing of a Wikipedia text
*
* @see WikipediaParser for the second pass
*/
public class TemplateParser extends AbstractParser {
private static final Pattern HTML_COMMENT_PATTERN = Pattern.compile("<!--(.*?)-->");
public final boolean fParseOnlySignature;
private final boolean fRenderTemplate;
private boolean fOnlyIncludeFlag;
public TemplateParser(String stringSource) {
this(stringSource, false, false);
}
public TemplateParser(String stringSource, boolean parseOnlySignature, boolean renderTemplate) {
super(stringSource);
fParseOnlySignature = parseOnlySignature;
fRenderTemplate = renderTemplate;
fOnlyIncludeFlag = false;
}
public static void parse(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean renderTemplate) throws IOException {
parse(rawWikitext, wikiModel, writer, false, renderTemplate);
}
/**
* Parse the wiki texts templates, comments and signatures into the given
* <code>StringBuilder</code>.
*
* @param rawWikitext
* @param wikiModel
* @param writer
* @param parseOnlySignature
* change only the signature string and ignore templates and comments
* parsing
* @param renderTemplate
*/
public static void parse(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean parseOnlySignature,
boolean renderTemplate) throws IOException {
parseRecursive(rawWikitext, wikiModel, writer, parseOnlySignature, renderTemplate);
}
// private static Pattern noinclude =
// Pattern.compile("<noinclude[^>]*>.*?<\\\\/noinclude[^>]*>");
//
// private static Pattern INCLUDEONLY_PATTERN =
// Pattern.compile("<includeonly[^>]*>(.*?)<\\/includeonly[^>]*>");
protected static void parseRecursive(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean parseOnlySignature,
boolean renderTemplate) throws IOException {
parseRecursive(rawWikitext, wikiModel, writer, parseOnlySignature, renderTemplate, null);
}
protected static void parseRecursive(String rawWikitext, IWikiModel wikiModel, Appendable writer, boolean parseOnlySignature,
boolean renderTemplate, HashMap<String, String> templateParameterMap) throws IOException {
try {
int level = wikiModel.incrementRecursionLevel();
if (level > Configuration.PARSER_RECURSION_LIMIT) {
writer.append("Error - recursion limit exceeded parsing templates.");
return;
}
// recursion limit on level is not sufficient as it is possible to recurse
// indefinitely at fixed level upper bound
if (wikiModel.incrementTemplateRecursionCount() > Configuration.TEMPLATE_RECURSION_LIMIT) {
// writer.append("Error - total recursion count limit (" +
// wikiModel.getTemplateRecursionCount() +
// ") exceeded parsing templates.");
return;
}
TemplateParser parser = new TemplateParser(rawWikitext, parseOnlySignature, renderTemplate);
parser.setModel(wikiModel);
StringBuilder sb = new StringBuilder(rawWikitext.length());
parser.runPreprocessParser(sb, false);
if (parseOnlySignature) {
writer.append(sb);
return;
}
int len = sb.length();
parser = new TemplateParser(sb.toString(), false, renderTemplate);
parser.setModel(wikiModel);
sb = new StringBuilder(len);
parser.runPreprocessParser(sb, true);
StringBuilder parameterBuffer = sb;
StringBuilder plainBuffer = sb;
if (templateParameterMap != null && (!templateParameterMap.isEmpty())) {
String preprocessedContent = parameterBuffer.toString();
WikipediaScanner scanner = new WikipediaScanner(preprocessedContent);
scanner.setModel(wikiModel);
parameterBuffer = scanner.replaceTemplateParameters(preprocessedContent, templateParameterMap);
if (parameterBuffer != null) {
plainBuffer = parameterBuffer;
}
}
parser = new TemplateParser(plainBuffer.toString(), parseOnlySignature, renderTemplate);
parser.setModel(wikiModel);
// parser.initialize(plainBuffer.toString());
sb = new StringBuilder(plainBuffer.length());
parser.runParser(sb);
if (!renderTemplate) {
String redirectedLink = AbstractParser.parseRedirect(sb.toString(), wikiModel);
if (redirectedLink != null) {
String redirectedContent = AbstractParser.getRedirectedTemplateContent(wikiModel, redirectedLink, null);
if (redirectedContent != null) {
parseRecursive(redirectedContent, wikiModel, writer, parseOnlySignature, renderTemplate);
return;
}
}
}
writer.append(sb);
return;
} catch (Exception e) {
e.printStackTrace();
writer.append(e.getClass().getSimpleName());
} catch (Error e) {
e.printStackTrace();
writer.append(e.getClass().getSimpleName());
} finally {
wikiModel.decrementRecursionLevel();
}
}
/**
* Preprocess parsing of the <code><includeonly></code>,
* <code><onlyinclude></code> and <code><noinclude></code> tags
*
* @param writer
* @param ignoreTemplateTags
* TODO
* @throws IOException
*/
protected void runPreprocessParser(StringBuilder writer, boolean ignoreTemplateTags) throws IOException {
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
try {
while (true) {
fCurrentCharacter = fSource[fCurrentPosition++];
// ---------Identify the next token-------------
switch (fCurrentCharacter) {
case '<':
int htmlStartPosition = fCurrentPosition;
if (!fParseOnlySignature && parseIncludeWikiTags(writer, ignoreTemplateTags)) {
continue;
}
fCurrentPosition = htmlStartPosition;
break;
case '~':
int tildeCounter = 0;
if (fSource[fCurrentPosition] == '~' && fSource[fCurrentPosition + 1] == '~') {
// parse signatures '~~~', '~~~~' or '~~~~~'
tildeCounter = 3;
try {
if (fSource[fCurrentPosition + 2] == '~') {
tildeCounter = 4;
if (fSource[fCurrentPosition + 3] == '~') {
tildeCounter = 5;
}
}
} catch (IndexOutOfBoundsException e1) {
// end of scanner text
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
fWikiModel.appendSignature(writer, tildeCounter);
fCurrentPosition += (tildeCounter - 1);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
}
}
if (!fWhiteStart) {
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition - 1;
}
}
// -----------------end switch while try--------------------
} catch (IndexOutOfBoundsException e) {
// end of scanner text
}
try {
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
}
} catch (IndexOutOfBoundsException e) {
// end of scanner text
}
}
protected void runParser(Appendable writer) throws IOException {
// int oldCurrentPosition = 0;
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
try {
while (true) {
// if (oldCurrentPosition >= fCurrentPosition) {
// System.out.println("stop stop: " + oldCurrentPosition + "--" +
// fStringSource);
// System.exit(-1);
// }
fCurrentCharacter = fSource[fCurrentPosition++];
// oldCurrentPosition = fCurrentPosition;
// ---------Identify the next token-------------
switch (fCurrentCharacter) {
case '{': // wikipedia template handling
if (!fParseOnlySignature && parseTemplateOrTemplateParameter(writer)) {
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
continue;
}
break;
case '<':
int htmlStartPosition = fCurrentPosition;
if (!fParseOnlySignature && parseSpecialWikiTags(writer)) {
continue;
}
fCurrentPosition = htmlStartPosition;
break;
case '~':
int tildeCounter = 0;
if (fSource[fCurrentPosition] == '~' && fSource[fCurrentPosition + 1] == '~') {
// parse signatures '~~~', '~~~~' or '~~~~~'
tildeCounter = 3;
try {
if (fSource[fCurrentPosition + 2] == '~') {
tildeCounter = 4;
if (fSource[fCurrentPosition + 3] == '~') {
tildeCounter = 5;
}
}
} catch (IndexOutOfBoundsException e1) {
// end of scanner text
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
fWikiModel.appendSignature(writer, tildeCounter);
fCurrentPosition += (tildeCounter - 1);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
}
}
if (!fWhiteStart) {
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition - 1;
}
}
// -----------------end switch while try--------------------
} catch (IndexOutOfBoundsException e) {
// end of scanner text
}
try {
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
} catch (IndexOutOfBoundsException e) {
// end of scanner text
}
}
/**
* See <a href=
* "http://en.wikipedia.org/wiki/Help:Template#Controlling_what_gets_transcluded"
* >Help:Template#Controlling what gets transcluded</a>
*
* @param writer
* @param ignoreTemplateTags
* TODO
* @return
* @throws IOException
*/
protected boolean parseIncludeWikiTags(StringBuilder writer, boolean ignoreTemplateTags) throws IOException {
try {
switch (fSource[fCurrentPosition]) {
case '!': // <!-- html comment -->
if (parseHTMLCommentTags(writer)) {
return true;
}
break;
default:
if (fSource[fCurrentPosition] != '/') {
// starting tag
int lessThanStart = fCurrentPosition - 1;
WikiTagNode tagNode = parseTag(fCurrentPosition);
if (tagNode != null) {
fCurrentPosition = tagNode.getEndPosition();
int tagStart = fCurrentPosition;
String tagName = tagNode.getTagName();
if (tagName.equals("nowiki")) {
if (readUntilIgnoreCase("</", "nowiki>")) {
return true;
}
} else if (tagName.equals("source")) {
if (readUntilIgnoreCase("</", "source>")) {
return true;
}
} else if (tagName.equals("math")) {
if (readUntilIgnoreCase("</", "math>")) {
return true;
}
}
if (ignoreTemplateTags) {
return false;
}
if (!isTemplate()) {
// not rendering a Template namespace directly
if (tagName.equals("includeonly")) {
if (readUntilIgnoreCase("</", "includeonly>")) {
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
}
fWhiteStart = true;
fWhiteStartPosition = tagStart;
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, 2 + "includeonly>".length(), true);
}
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
}
fWhiteStart = false;
// fWhiteStartPosition = tagStart;
fCurrentPosition = fStringSource.length();
return true;
} else if (tagName.equals("noinclude")) {
if (readUntilIgnoreCase("</", "noinclude>")) {
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
}
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
return true;
} else if (tagName.equals("onlyinclude")) {
if (readUntilIgnoreCase("</", "onlyinclude>")) {
if (!fOnlyIncludeFlag) {
// delete the content, which is already added
writer.delete(0, writer.length());
fOnlyIncludeFlag = true;
}
// appendContent(writer, fWhiteStart, fWhiteStartPosition,
// fCurrentPosition - lessThanStart);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
appendContent(writer, fWhiteStart, fWhiteStartPosition, 2 + "onlyinclude>".length(), true);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
return true;
}
} else {
if (tagName.equals("noinclude")) {
if (readUntilIgnoreCase("</", "noinclude>")) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
appendContent(writer, fWhiteStart, fWhiteStartPosition, 2 + "noinclude>".length(), true);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
return true;
} else if (tagName.equals("includeonly")) {
if (readUntilIgnoreCase("</", "includeonly>")) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = false;
// fWhiteStartPosition = tagStart;
fCurrentPosition = fStringSource.length();
return true;
} else if (tagName.equals("onlyinclude")) {
if (readUntilIgnoreCase("</", "onlyinclude>")) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - lessThanStart, true);
fWhiteStart = true;
fWhiteStartPosition = tagStart;
return true;
}
}
}
}
}
} catch (IndexOutOfBoundsException e) {
// do nothing
}
return false;
}
protected boolean parseSpecialWikiTags(Appendable writer) throws IOException {
try {
switch (fSource[fCurrentPosition]) {
case '!': // <!-- html comment -->
if (parseHTMLCommentTags(writer)) {
return true;
}
break;
default:
if (fSource[fCurrentPosition] != '/') {
// starting tag
WikiTagNode tagNode = parseTag(fCurrentPosition);
if (tagNode != null) {
fCurrentPosition = tagNode.getEndPosition();
String tagName = tagNode.getTagName();
if (tagName.equals("nowiki")) {
if (readUntilIgnoreCase("</", "nowiki>")) {
return true;
}
} else if (tagName.equals("source")) {
if (readUntilIgnoreCase("</", "source>")) {
return true;
}
} else if (tagName.equals("math")) {
if (readUntilIgnoreCase("</", "math>")) {
return true;
}
}
}
}
}
} catch (IndexOutOfBoundsException e) {
// do nothing
}
return false;
}
protected void appendContent(Appendable writer, boolean whiteStart, final int whiteStartPosition, final int diff,
boolean stripHTMLComments) throws IOException {
if (whiteStart) {
try {
final int whiteEndPosition = fCurrentPosition - diff;
int count = whiteEndPosition - whiteStartPosition;
if (count > 0) {
if (stripHTMLComments) {
writer.append(HTML_COMMENT_PATTERN.matcher(fStringSource.substring(whiteStartPosition, whiteEndPosition))
.replaceAll(""));
} else {
writer.append(fStringSource, whiteStartPosition, whiteEndPosition);
}
}
} finally {
fWhiteStart = false;
}
}
}
private boolean parseTemplateOrTemplateParameter(Appendable writer) throws IOException {
if (fSource[fCurrentPosition] == '{') {
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
int startTemplatePosition = ++fCurrentPosition;
if (fSource[fCurrentPosition] == '{' && fSource[fCurrentPosition + 1] != '{') {
// parse template parameters
int[] templateEndPosition = findNestedParamEnd(fSource, fCurrentPosition + 1);
if (templateEndPosition[0] < 0) {
if (templateEndPosition[1] < 0) {
--fCurrentPosition;
} else {
writer.append('{');
++fCurrentPosition;
return parseTemplate(writer, startTemplatePosition + 1, templateEndPosition[1]);
}
} else {
return parseTemplateParameter(writer, startTemplatePosition, templateEndPosition[0]);
}
} else {
int templateEndPosition = findNestedTemplateEnd(fSource, fCurrentPosition);
if (templateEndPosition < 0) {
fCurrentPosition--;
} else {
return parseTemplate(writer, startTemplatePosition, templateEndPosition);
}
}
}
return false;
}
/**
* Parse a single template {{...}}
*
* @param writer
* @param startTemplatePosition
* @param templateEndPosition
* @return
* @throws IOException
*/
private boolean parseTemplate(Appendable writer, int startTemplatePosition, int templateEndPosition) throws IOException {
fCurrentPosition = templateEndPosition;
// insert template handling
int endPosition = fCurrentPosition;
String plainContent = null;
int endOffset = fCurrentPosition - 2;
String function = checkParserFunction(startTemplatePosition, endOffset);
if (function != null) {
// System.out.println("Function: " + function);
// if (function.contains("[[Template")) {
// System.out.println("Function: " + fStringSource);
// }
ITemplateFunction templateFunction = fWikiModel.getTemplateFunction(function);
if (templateFunction != null) {
// if (function.charAt(0) == '#') {
// #if:, #ifeq:,...
plainContent = templateFunction.parseFunction(fSource, fCurrentPosition, endOffset, fWikiModel);
fCurrentPosition = endPosition;
if (plainContent != null) {
TemplateParser.parseRecursive(plainContent, fWikiModel, writer, false, false);
return true;
}
return true;
}
fCurrentPosition = endOffset + 2;
}
Object[] objs = createParameterMap(fSource, startTemplatePosition, fCurrentPosition - startTemplatePosition - 2);
HashMap<String, String> map = (HashMap<String, String>) objs[0];
String templateName = ((String) objs[1]).trim();
String cacheKey = templateName + objs[2];
Map<String, String> templateCallsCache = null;
if (cacheKey.length() < 256 && fWikiModel instanceof IConfiguration) {
IConfiguration config = (IConfiguration) fWikiModel;
templateCallsCache = config.getTemplateCallsCache();
if (templateCallsCache != null) {
String value = templateCallsCache.get(cacheKey);
if (value != null) {
// System.out.println("Cache key: " + cacheKey);
writer.append(value);
return true;
}
}
}
if (templateName.length() > 0 && templateName.charAt(0) == ':') {
// invalidate cache:
templateCallsCache = null;
plainContent = fWikiModel.getRawWikiContent("", templateName.substring(1), map);
} else {
fWikiModel.addTemplate(templateName);
plainContent = fWikiModel.getRawWikiContent(fWikiModel.getTemplateNamespace(), templateName, map);
}
fCurrentPosition = endPosition;
if (plainContent != null) {
StringBuilder templateBuffer = new StringBuilder(plainContent.length());
TemplateParser.parseRecursive(plainContent.trim(), fWikiModel, templateBuffer, false, false, map);
if (templateCallsCache != null) {
// save this template call in the cache
String cacheValue = templateBuffer.toString();
templateCallsCache.put(cacheKey, cacheValue);
writer.append(cacheValue);
} else {
writer.append(templateBuffer);
}
return true;
}
// if no template found insert plain template name string:
// writer.append("[[" + fWikiModel.getTemplateNamespace() + ":" +
// templateName + "]]");
writer.append("{{" + templateName + "}}");
return true;
}
/**
* Parse a single template parameter {{{...}}}
*
* @param writer
* @param startTemplatePosition
* @param templateEndPosition
* @return
* @throws IOException
*/
private boolean parseTemplateParameter(Appendable writer, int startTemplatePosition, int templateEndPosition) throws IOException {
String plainContent = fStringSource.substring(startTemplatePosition - 2, templateEndPosition);
if (plainContent != null) {
fCurrentPosition = templateEndPosition;
WikipediaScanner scanner = new WikipediaScanner(plainContent);
scanner.setModel(fWikiModel);
StringBuilder plainBuffer = scanner.replaceTemplateParameters(plainContent, null);
if (plainBuffer == null) {
writer.append(plainContent);
return true;
}
TemplateParser.parseRecursive(plainBuffer.toString().trim(), fWikiModel, writer, false, false);
return true;
}
return false;
}
/**
* Create a map from the parameters defined in a template call
*
* @return the templates parameter map at index [0] and the template name at
* index [1]
*
*/
private static Object[] createParameterMap(char[] src, int startOffset, int len) {
Object[] objs = new Object[3];
HashMap<String, String> map = new HashMap<String, String>();
StringBuilder buf = new StringBuilder(len);
objs[0] = map;
int currOffset = startOffset;
int endOffset = startOffset + len;
List<String> resultList = new ArrayList<String>();
resultList = splitByPipe(src, currOffset, endOffset, resultList);
if (resultList.size() <= 1) {
// set the templates name
objs[1] = new String(src, startOffset, len);
objs[2] = "";
return objs;
}
objs[1] = resultList.get(0);
for (int i = 1; i < resultList.size(); i++) {
if (i == resultList.size() - 1) {
createSingleParameter(i, resultList.get(i), map, buf, true);
} else {
createSingleParameter(i, resultList.get(i), map, buf, false);
}
}
objs[2] = buf.toString();
return objs;
}
/**
* Create a single parameter defined in a template call and add it to the
* parameters map
*
*/
private static void createSingleParameter(int parameterCounter, String srcString, HashMap<String, String> map, StringBuilder buf,
boolean trimNewlineRight) {
int currOffset = 0;
char[] src = srcString.toCharArray();
int endOffset = srcString.length();
char ch;
String parameter = null;
String value;
boolean equalCharParsed = false;
int lastOffset = currOffset;
int[] temp = new int[] { -1, -1 };
try {
while (currOffset < endOffset) {
ch = src[currOffset++];
if (ch == '[' && src[currOffset] == '[') {
currOffset++;
temp[0] = findNestedEnd(src, '[', ']', currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
}
} else if (ch == '{' && src[currOffset] == '{') {
currOffset++;
if (src[currOffset] == '{' && src[currOffset + 1] != '{') {
currOffset++;
temp = findNestedParamEnd(src, currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
} else {
currOffset--;
temp[0] = findNestedTemplateEnd(src, currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
}
}
} else {
temp[0] = findNestedTemplateEnd(src, currOffset);
if (temp[0] >= 0) {
currOffset = temp[0];
}
}
} else if (ch == '=') {
if (!equalCharParsed) {
parameter = srcString.substring(lastOffset, currOffset - 1).trim();
lastOffset = currOffset;
}
equalCharParsed = true;
}
}
} catch (IndexOutOfBoundsException e) {
} finally {
if (currOffset > lastOffset) {
if (trimNewlineRight) {
value = Utils.trimNewlineRight(srcString.substring(lastOffset, currOffset));
} else {
value = srcString.substring(lastOffset, currOffset).trim();
}
buf.append("|" + value);
map.put(Integer.toString(parameterCounter), value);
if (parameter != null) {
map.put(parameter, value);
}
}
}
}
/**
* Check if this template contains a template function
*
* Note: repositions this#fCurrentPosition behind the parser function string
* if possible
*
* @param startOffset
* @param endOffset
* @return the parser function name (without the # character) or
* <code>null</code> if no parser function can be found in this
* template
*/
private String checkParserFunction(int startOffset, int endOffset) {
// String function = null;
int currOffset = startOffset;
int functionStart = startOffset;
char ch;
while (currOffset < endOffset) {
ch = fSource[currOffset++];
if (Character.isLetter(ch) || ch == '#' || ch == '$') {
functionStart = currOffset - 1;
while (currOffset < endOffset) {
ch = fSource[currOffset++];
if (ch == ':') {
fCurrentPosition = currOffset;
return fStringSource.substring(functionStart, currOffset - 1);
} else if (!Character.isLetterOrDigit(ch) && ch != '$') {
return null;
}
}
break;
}
}
return null;
}
protected boolean parseHTMLCommentTags(Appendable writer) throws IOException {
int temp = readWhitespaceUntilStartOfLine(2);
String htmlCommentString = fStringSource.substring(fCurrentPosition - 1, fCurrentPosition + 3);
if (htmlCommentString.equals("<!--")) {
if (temp >= 0) {
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, fCurrentPosition - temp - 1, true);
}
} else {
if (!fOnlyIncludeFlag) {
appendContent(writer, fWhiteStart, fWhiteStartPosition, 1, true);
}
}
fCurrentPosition += 3;
if (readUntil("-->")) {
if (temp >= 0) {
temp = readWhitespaceUntilEndOfLine(0);
if (temp >= 0) {
fCurrentPosition++;
}
}
fWhiteStart = true;
fWhiteStartPosition = fCurrentPosition;
return true;
}
}
return false;
}
@Override
public void runParser() {
// do nothing here
}
@Override
public void setNoToC(boolean noToC) {
// do nothing here
}
public boolean isTemplate() {
return fRenderTemplate;
}
}