private int doRead()

in src/main/java/org/apache/sling/scripting/javascript/io/EspReader.java [398:719]


    private int doRead() throws IOException {

        // we return out of the loop, if we find a character passing the filter
        for (;;) {

            // Get a character from the input, which may well have been
            // injected using the unread() method
            int c = input.read();

            // catch EOF
            if (c < 0) {

                // if a template text line is still incomplete, inject
                // proper line ending and continue until this has been returned
                if (!lineStart && state == PARSE_STATE_ESP) {
                    doVerbatim("\");"); // line ending injection
                    lineStart = true; // mark the line having ended
                    continue; // let's start read the injection
                }

                return c; // return the marker, we're done
            }

            // Do the finite state machine
            switch (state) {

                // NOTE :
                // - continue means ignore current character, read next
                // - break means return current character

                // Template text state - text is wrapped in out.write()
                case PARSE_STATE_ESP:
                    if (c == '$') { // might start EL-like ECMA expr
                    	int c2 = input.read();
                    	if (c2 == '{') {
                            // ECMA expression ${ ... }
                            pushState(PARSE_STATE_ECMA_EXPR_COMPACT);
                            startWrite(null);
                            if (!lineStart) {
                                doVerbatim("\");");
                            }
                            continue;
                    	}
                    	 
                    	input.unread(c2);

                    } else  if (c == '<') { // might start ECMA code/expr, ESP comment or JSP comment
                        int c2 = input.read();
                        int c3 = input.read();

                        if (c2 == '%') {
                            // ECMA or JSP comment

                            if (c3 == '=') {

                                // ECMA expression <%= ... %>
                                pushState(PARSE_STATE_ECMA_EXPR);
                                startWrite(null);
                                if (!lineStart) {
                                    doVerbatim("\");");
                                }
                                continue;

                            } else if (c3 == '-') {

                                // (Possible) JSP Comment <%-- ... --%>
                                int c4 = input.read();
                                if (c4 == '-') {
                                    pushState(PARSE_STATE_JSP_COMMENT);
                                    continue;
                                }
                                input.unread(c4);

                            }

                            // We only get here if we are sure about ECMA

                            // ECMA code <% ... %>
                            input.unread(c3);
                            pushState(PARSE_STATE_ECMA);
                            if (!lineStart) {
                                doVerbatim("\");");
                            }
                            continue;

                        }

                        // Nothing special, push back read ahead
                        input.unread(c3);
                        input.unread(c2);

                        // End of template text line
                    } else if (c == '\r' || c == '\n') {
                        String lineEnd; // will be injected

                        // Check for real CRLF
                        if (c == '\r') {
                            int c2 = input.read();
                            if (c2 != '\n') {
                                input.unread(c2);
                                lineEnd = "\\r";
                            } else {
                                lineEnd = "\\r\\n";
                            }
                        } else {
                            lineEnd = "\\n";
                        }

                        // Only write line ending if not empty
                        if (!lineStart) {
                            doVerbatim("\");\n");
                            doVerbatim(lineEnd);
                            lineStart = true;

                        } else { // if (lineEnd.length() > 1) {
                            // no matter what line ending we have, make it LF
                            doVerbatim("\");\n");
                            doVerbatim(lineEnd);
                            startWrite("\"");
                        }

                        continue;

                        // template text is wrapped with double quotes, which
                        // when occurring in the text must be escaped.
                        // We also escape the escape character..
                    } else if (c == '"' || c == '\\') {

                        doVerbatim(String.valueOf((char) c));
                        c = '\\';

                    }

                    // If in template text at the beginning of a line
                    if (lineStart) {
                        lineStart = false;
                        startWrite("\"" + (char) c);
                        continue;
                    }

                    break;

                // Reading ECMA code or and ECMA expression
                case PARSE_STATE_ECMA_EXPR:
                case PARSE_STATE_ECMA:

                    if (c == '%') {

                        // might return to PARSE_STATE_ESP
                        int c2 = input.read();
                        if (c2 == '>') {

                            // An expression is wrapped in out.write()
                            if (popState() == PARSE_STATE_ECMA_EXPR) {
                                doVerbatim(");");
                            }

                            // next ESP needs out.write(
                            lineStart = true;

                            continue;

                        }

                        // false alert, push back
                        input.unread(c2);

                    } else if (c == '/') {

                        // might be ECMA Comment
                        int c2 = input.read();
                        if (c2 == '/') {
                            // single line comment
                            pushState(PARSE_STATE_ECMA_COMMENTL);
                        } else if (c2 == '*') {
                            // multiline comment
                            pushState(PARSE_STATE_ECMA_COMMENT);
                        }

                        // false alert, push back
                        input.unread(c2);

                    } else if (c == '\'' || c == '"') {

                        // an ECMA string
                        escape = false; // start unescaped
                        quoteChar = (char) c; // to recognize the end
                        pushState(PARSE_STATE_QUOTE);

                    }
                    break;

                // reading compact (EL-like) ECMA Expression
                case PARSE_STATE_ECMA_EXPR_COMPACT:
                    if (c == '}') { //might be the end of a compact expression
                        // An expression is wrapped in out.write()
                        popState();
                        doVerbatim(");");

                        // next ESP needs out.write(
                        lineStart = true;

                        continue;

                    }
                    break;

                // Reading a JSP comment, only returning line endings
                case PARSE_STATE_JSP_COMMENT:

                    // JSP comments end complexly with --%>
                    if (c == '-') {
                        int c2 = input.read();
                        if (c2 == '-') {
                            int c3 = input.read();
                            if (c3 == '%') {
                                int c4 = input.read();
                                if (c4 == '>') {

                                    // we really reached the end ...
                                    popState();
                                    continue;

                                }
                                input.unread(c4);
                            }
                            input.unread(c3);
                        }
                        input.unread(c2);

                        // well, not definitely correct but reasonably accurate
                        // ;-)
                    } else if (c == '\r' || c == '\n') {

                        // terminate an open template line
                        if (!lineStart) {
                            input.unread(c); // push back the character
                            doVerbatim("\");"); // insert ");
                            lineStart = true; // mark the line start
                            continue; // Force read of the "
                        }

                        break;
                    }

                    // continue reading another character in the comment
                    continue;

                    // Read an ECMA string upto the ending quote character
                case PARSE_STATE_QUOTE:

                    // if unescaped quote character
                    if (c == quoteChar && !escape) {
                        popState();
                    } else {
                        // mark escape - only if not already escaped (bug 7079)
                        escape = c == '\\' && !escape;
                    }

                    break;

                // Return characters unfiltered
                case PARSE_STATE_VERBATIM:

                    // Go back to previous state if all characters read
                    if (--verbatimChars < 0) {
                        popState();
                    }

                    break;

                // Return an ECMA multiline comment, ending with */
                case PARSE_STATE_ECMA_COMMENT:

                    // Might be the end of the comment
                    if (c == '*') {
                        int c2 = input.read();
                        if (c2 == '/') {
                            popState(); // back to previous
                            doVerbatim("/"); // return slash verbatim
                        } else {
                            input.unread(c2);
                        }
                    }

                    break;

                // Return an ECMA single line comment, ending with end of line
                case PARSE_STATE_ECMA_COMMENTL:

                    // CRLF recognition
                    if (c == '\r') {
                        int c2 = input.read();
                        if (c2 == '\n') {
                            popState();
                        }
                        input.unread(c2);

                        // LF only line end
                    } else if (c == '\n') {
                        popState();
                    }

                    break;
                    
                // What ???!!!
                default:

                    // we warn and go back to default state
                    log.warn("doRead(): unknown state " + state);
                    state = PARSE_STATE_ESP;

                    break;

            } // switch

            // Exiting the switch normally we return the current character
            return c;

        } // for(;;)

    }