* TODO Note that this method does not enforce rules about local versus
* global tags!
*/
private Token scanTag() {
// See the specification for details.
Mark startMark = reader.getMark();
// Determine the type of tag property based on the first character
// encountered
char ch = reader.peek(1);
String handle = null;
String suffix = null;
// Verbatim tag! (c-verbatim-tag)
if (ch == '<') {
// Skip the exclamation mark and >, then read the tag suffix (as
// a URI).
reader.forward(2);
suffix = scanTagUri("tag", startMark);
if (reader.peek() != '>') {
// If there are any characters between the end of the tag-suffix
// URI and the closing >, then an error has occurred.
throw new ScannerException("while scanning a tag", startMark,
"expected '>', but found '" + reader.peek() + "' (" + ((int) reader.peek())
+ ")", reader.getMark());
}
reader.forward();
} else if (Constant.NULL_BL_T_LINEBR.has(ch)) {
// A NUL, blank, tab, or line-break means that this was a
// c-ns-non-specific tag.
suffix = "!";
reader.forward();
} else {
// Any other character implies c-ns-shorthand-tag type.
// Look ahead in the stream to determine whether this tag property
// is of the form !foo or !foo!bar.
int length = 1;
boolean useHandle = false;
while (Constant.NULL_BL_LINEBR.hasNo(ch)) {
if (ch == '!') {
useHandle = true;
break;
}
length++;
ch = reader.peek(length);
}
handle = "!";
// If we need to use a handle, scan it in; otherwise, the handle is
// presumed to be '!'.
if (useHandle) {
handle = scanTagHandle("tag", startMark);
} else {
handle = "!";
reader.forward();
}
suffix = scanTagUri("tag", startMark);
}
ch = reader.peek();
// Check that the next character is allowed to follow a tag-property;
// if it is not, raise the error.
if (Constant.NULL_BL_LINEBR.hasNo(ch)) {
throw new ScannerException("while scanning a tag", startMark,
"expected ' ', but found '" + ch + "' (" + ((int) ch) + ")", reader.getMark());
}
TagTuple value = new TagTuple(handle, suffix);
Mark endMark = reader.getMark();
return new TagToken(value, startMark, endMark);
}