in src/main/core-api/java/com/mysql/cj/util/StringUtils.java [594:727]
private static int indexOfNextChar(int startingPosition, int stopPosition, String searchIn, String openingMarkers, String closingMarkers,
String overridingMarkers, Set<SearchMode> searchMode) {
if (searchIn == null) {
return -1;
}
int searchInLength = searchIn.length();
if (startingPosition >= searchInLength) {
return -1;
}
char c0 = Character.MIN_VALUE; // current char
char c1 = searchIn.charAt(startingPosition); // lookahead(1)
char c2 = startingPosition + 1 < searchInLength ? searchIn.charAt(startingPosition + 1) : Character.MIN_VALUE; // lookahead(2)
for (int i = startingPosition; i <= stopPosition; i++) {
c0 = c1;
c1 = c2;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
boolean dashDashCommentImmediateEnd = false;
int markerIndex = -1;
if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') {
i++; // next char is escaped, skip it
// reset lookahead
c1 = c2;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
} else if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (markerIndex = openingMarkers.indexOf(c0)) != -1) {
// marker found, skip until closing, while being aware of nested markers if opening and closing markers are distinct
int nestedMarkersCount = 0;
char openingMarker = c0;
char closingMarker = closingMarkers.charAt(markerIndex);
boolean outerIsAnOverridingMarker = overridingMarkers.indexOf(openingMarker) != -1;
while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != closingMarker || nestedMarkersCount != 0)) {
if (!outerIsAnOverridingMarker && overridingMarkers.indexOf(c0) != -1) {
// there is an overriding marker that needs to be consumed before returning to the previous marker
int overridingMarkerIndex = openingMarkers.indexOf(c0); // overridingMarkers must be a sub-list of openingMarkers
int overridingNestedMarkersCount = 0;
char overridingOpeningMarker = c0;
char overridingClosingMarker = closingMarkers.charAt(overridingMarkerIndex);
while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != overridingClosingMarker || overridingNestedMarkersCount != 0)) {
// do as before, but this marker can't be overridden
if (c0 == overridingOpeningMarker) {
overridingNestedMarkersCount++;
} else if (c0 == overridingClosingMarker) {
overridingNestedMarkersCount--;
} else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') {
i++; // next char is escaped, skip it
}
}
} else if (c0 == openingMarker) {
nestedMarkersCount++;
} else if (c0 == closingMarker) {
nestedMarkersCount--;
} else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') {
i++; // next char is escaped, skip it
}
}
// reset lookahead
c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
} else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '/' && c1 == '*') {
if (c2 != '!') {
// comments block found, skip until end of block ("*/") (backslash escape doesn't work on comments)
i++; // move to next char ('*')
while (++i <= stopPosition
&& (searchIn.charAt(i) != '*' || (i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE) != '/')) {
// continue
}
i++; // move to next char ('/')
} else {
// special non-comments block found, move to end of opening marker ("/*![12345]")
i++; // move to next char ('*')
i++; // move to next char ('!')
// check if a 5 digits MySQL version reference follows, if so skip them
int j = 1;
for (; j <= NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; j++) {
if (i + j >= searchInLength || !Character.isDigit(searchIn.charAt(i + j))) {
break;
}
}
if (j == NON_COMMENTS_MYSQL_VERSION_REF_LENGTH) {
i += NON_COMMENTS_MYSQL_VERSION_REF_LENGTH;
}
}
// reset lookahead
c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
} else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '*' && c1 == '/') {
// special non-comments block closing marker ("*/") found - assume that if we get it here it's because it
// belongs to a non-comments block ("/*!"), otherwise the query should be misspelled as nesting comments isn't allowed.
i++; // move to next char ('/')
// reset lookahead
c1 = c2;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
} else if (searchMode.contains(SearchMode.SKIP_LINE_COMMENTS)
&& ((c0 == '-' && c1 == '-' && (Character.isWhitespace(c2) || (dashDashCommentImmediateEnd = c2 == ';') || c2 == Character.MIN_VALUE))
|| c0 == '#')) {
if (dashDashCommentImmediateEnd) {
// comments line found but closed immediately by query delimiter marker
i++; // move to next char ('-')
i++; // move to next char (';')
// reset lookahead
c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE;
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
} else {
// comments line found, skip until eol (backslash escape doesn't work on comments)
while (++i <= stopPosition && (c0 = searchIn.charAt(i)) != '\n' && c0 != '\r') {
// continue
}
// reset lookahead
c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE;
if (c0 == '\r' && c1 == '\n') {
// \r\n sequence found
i++; // skip next char ('\n')
c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE;
}
c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE;
}
} else if (!searchMode.contains(SearchMode.SKIP_WHITE_SPACE) || !Character.isWhitespace(c0)) {
return i;
}
}
return -1;
}