in doxia-modules/doxia-module-apt/src/main/java/org/apache/maven/doxia/module/apt/AptParser.java [295:554]
protected void doTraverseText(String text, int begin, int end, Sink sink) throws AptParseException {
boolean anchor = false;
boolean link = false;
boolean italic = false;
boolean bold = false;
boolean monospaced = false;
StringBuilder buffer = new StringBuilder(end - begin);
for (int i = begin; i < end; ++i) {
char c = text.charAt(i);
switch (c) {
case BACKSLASH:
if (i + 1 < end) {
char escaped = text.charAt(i + 1);
switch (escaped) {
case SPACE:
++i;
flushTraversed(buffer, sink);
sink.nonBreakingSpace();
break;
case '\r':
case '\n':
++i;
// Skip white space which may follow a line break.
while (i + 1 < end && Character.isWhitespace(text.charAt(i + 1))) {
++i;
}
flushTraversed(buffer, sink);
sink.lineBreak();
break;
case BACKSLASH:
case PIPE:
case COMMENT:
case EQUAL:
case MINUS:
case PLUS:
case STAR:
case LEFT_SQUARE_BRACKET:
case RIGHT_SQUARE_BRACKET:
case LESS_THAN:
case GREATER_THAN:
case LEFT_CURLY_BRACKET:
case RIGHT_CURLY_BRACKET:
++i;
buffer.append(escaped);
break;
case 'x':
if (i + 3 < end && isHexChar(text.charAt(i + 2)) && isHexChar(text.charAt(i + 3))) {
int value = '?';
try {
value = Integer.parseInt(text.substring(i + 2, i + 4), 16);
} catch (NumberFormatException e) {
LOGGER.debug("Not a number: {}", text.substring(i + 2, i + 4));
}
i += 3;
buffer.append((char) value);
} else {
buffer.append(BACKSLASH);
}
break;
case 'u':
if (i + 5 < end
&& isHexChar(text.charAt(i + 2))
&& isHexChar(text.charAt(i + 3))
&& isHexChar(text.charAt(i + 4))
&& isHexChar(text.charAt(i + 5))) {
int value = '?';
try {
value = Integer.parseInt(text.substring(i + 2, i + 6), 16);
} catch (NumberFormatException e) {
LOGGER.debug("Not a number: {}", text.substring(i + 2, i + 6));
}
i += 5;
buffer.append((char) value);
} else {
buffer.append(BACKSLASH);
}
break;
default:
if (isOctalChar(escaped)) {
int octalChars = 1;
if (isOctalChar(charAt(text, end, i + 2))) {
++octalChars;
if (isOctalChar(charAt(text, end, i + 3))) {
++octalChars;
}
}
int value = '?';
try {
value = Integer.parseInt(text.substring(i + 1, i + 1 + octalChars), 8);
} catch (NumberFormatException e) {
LOGGER.debug("Not a number: {}", text.substring(i + 1, i + 1 + octalChars));
}
i += octalChars;
buffer.append((char) value);
} else {
buffer.append(BACKSLASH);
}
}
} else {
buffer.append(BACKSLASH);
}
break;
case LEFT_CURLY_BRACKET: /*}*/
if (!anchor && !link) {
if (i + 1 < end && text.charAt(i + 1) == LEFT_CURLY_BRACKET /*}*/) {
++i;
link = true;
flushTraversed(buffer, sink);
String linkAnchor = null;
if (i + 1 < end && text.charAt(i + 1) == LEFT_CURLY_BRACKET /*}*/) {
++i;
StringBuilder buf = new StringBuilder();
i = skipTraversedLinkAnchor(text, i + 1, end, buf);
linkAnchor = buf.toString();
}
if (linkAnchor == null) {
linkAnchor = getTraversedLink(text, i + 1, end);
}
if (AptUtils.isInternalLink(linkAnchor)) {
linkAnchor = "#" + linkAnchor;
}
int hashIndex = linkAnchor.indexOf("#");
if (hashIndex != -1 && !AptUtils.isExternalLink(linkAnchor)) {
String hash = linkAnchor.substring(hashIndex + 1);
if (hash.endsWith(".html") && !hash.startsWith("./")) {
LOGGER.debug("Ambiguous link '{}'. If this is a local link, prepend \"./\"!", hash);
}
// link##anchor means literal
if (hash.startsWith("#")) {
linkAnchor = linkAnchor.substring(0, hashIndex) + hash;
} else if (!DoxiaUtils.isValidId(hash)) {
linkAnchor = linkAnchor.substring(0, hashIndex) + "#" + DoxiaUtils.encodeId(hash);
LOGGER.debug("Modified invalid link '{}' to '{}'", hash, linkAnchor);
}
}
sink.link(linkAnchor);
} else {
anchor = true;
flushTraversed(buffer, sink);
String linkAnchor = getTraversedAnchor(text, i + 1, end);
linkAnchor = DoxiaUtils.encodeId(linkAnchor);
sink.anchor(linkAnchor);
}
} else {
buffer.append(c);
}
break;
case /*{*/ RIGHT_CURLY_BRACKET:
if (link && i + 1 < end && text.charAt(i + 1) == /*{*/ RIGHT_CURLY_BRACKET) {
++i;
link = false;
flushTraversed(buffer, sink);
sink.link_();
} else if (anchor) {
anchor = false;
flushTraversed(buffer, sink);
sink.anchor_();
} else {
buffer.append(c);
}
break;
case LESS_THAN:
if (!italic && !bold && !monospaced) {
if (i + 1 < end && text.charAt(i + 1) == LESS_THAN) {
if (i + 2 < end && text.charAt(i + 2) == LESS_THAN) {
i += 2;
monospaced = true;
flushTraversed(buffer, sink);
sink.monospaced();
} else {
++i;
bold = true;
flushTraversed(buffer, sink);
sink.bold();
}
} else {
italic = true;
flushTraversed(buffer, sink);
sink.italic();
}
} else {
buffer.append(c);
}
break;
case GREATER_THAN:
if (monospaced
&& i + 2 < end
&& text.charAt(i + 1) == GREATER_THAN
&& text.charAt(i + 2) == GREATER_THAN) {
i += 2;
monospaced = false;
flushTraversed(buffer, sink);
sink.monospaced_();
} else if (bold && i + 1 < end && text.charAt(i + 1) == GREATER_THAN) {
++i;
bold = false;
flushTraversed(buffer, sink);
sink.bold_();
} else if (italic) {
italic = false;
flushTraversed(buffer, sink);
sink.italic_();
} else {
buffer.append(c);
}
break;
default:
if (Character.isWhitespace(c)) {
buffer.append(SPACE);
// Skip to the last char of a sequence of white spaces.
while (i + 1 < end && Character.isWhitespace(text.charAt(i + 1))) {
++i;
}
} else {
buffer.append(c);
}
}
}
if (monospaced) {
throw new AptParseException("missing '" + MONOSPACED_END_MARKUP + "'");
}
if (bold) {
throw new AptParseException("missing '" + BOLD_END_MARKUP + "'");
}
if (italic) {
throw new AptParseException("missing '" + ITALIC_END_MARKUP + "'");
}
if (link) {
throw new AptParseException("missing '" + LINK_END_MARKUP + "'");
}
if (anchor) {
throw new AptParseException("missing '" + ANCHOR_END_MARKUP + "'");
}
flushTraversed(buffer, sink);
}