private static int indexOfNextChar()

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;
    }