FileDocCategorySizeDatePackage
ExpressionTokenizer.javaAPI DocGlassfish v2 API6808Fri May 04 22:32:20 BST 2007org.apache.catalina.ssi

ExpressionTokenizer.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * Portions Copyright Apache Software Foundation.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.apache.catalina.ssi;


/**
 * Parses an expression string to return the individual tokens. This is
 * patterned similar to the StreamTokenizer in the JDK but customized for SSI
 * conditional expression parsing.
 * 
 * @version $Revision: 1.2 $
 * @author Paul Speed
 */
public class ExpressionTokenizer {
    public static final int TOKEN_STRING = 0;
    public static final int TOKEN_AND = 1;
    public static final int TOKEN_OR = 2;
    public static final int TOKEN_NOT = 3;
    public static final int TOKEN_EQ = 4;
    public static final int TOKEN_NOT_EQ = 5;
    public static final int TOKEN_RBRACE = 6;
    public static final int TOKEN_LBRACE = 7;
    public static final int TOKEN_GE = 8;
    public static final int TOKEN_LE = 9;
    public static final int TOKEN_GT = 10;
    public static final int TOKEN_LT = 11;
    public static final int TOKEN_END = 12;
    private char[] expr;
    private String tokenVal = null;
    private int index;
    private int length;


    /**
     * Creates a new parser for the specified expression.
     */
    public ExpressionTokenizer(String expr) {
        this.expr = expr.trim().toCharArray();
        this.length = this.expr.length;
    }


    /**
     * Returns true if there are more tokens.
     */
    public boolean hasMoreTokens() {
        return index < length;
    }


    /**
     * Returns the current index for error reporting purposes.
     */
    public int getIndex() {
        return index;
    }


    protected boolean isMetaChar(char c) {
        return Character.isWhitespace(c) || c == '(' || c == ')' || c == '!'
                || c == '<' || c == '>' || c == '|' || c == '&' || c == '=';
    }


    /**
     * Returns the next token type and initializes any state variables
     * accordingly.
     */
    public int nextToken() {
        // Skip any leading white space
        while (index < length && Character.isWhitespace(expr[index]))
            index++;
        // Clear the current token val
        tokenVal = null;
        if (index == length) return TOKEN_END; // End of string
        int start = index;
        char currentChar = expr[index];
        char nextChar = (char)0;
        index++;
        if (index < length) nextChar = expr[index];
        // Check for a known token start
        switch (currentChar) {
            case '(' :
                return TOKEN_LBRACE;
            case ')' :
                return TOKEN_RBRACE;
            case '=' :
                return TOKEN_EQ;
            case '!' :
                if (nextChar == '=') {
                    index++;
                    return TOKEN_NOT_EQ;
                } else {
                    return TOKEN_NOT;
                }
            case '|' :
                if (nextChar == '|') {
                    index++;
                    return TOKEN_OR;
                }
                break;
            case '&' :
                if (nextChar == '&') {
                    index++;
                    return TOKEN_AND;
                }
                break;
            case '>' :
                if (nextChar == '=') {
                    index++;
                    return TOKEN_GE; // Greater than or equal
                } else {
                    return TOKEN_GT; // Greater than
                }
            case '<' :
                if (nextChar == '=') {
                    index++;
                    return TOKEN_LE; // Less than or equal
                } else {
                    return TOKEN_LT; // Less than
                }
            default :
                // Otherwise it's a string
                break;
        }
        int end = index;
        // If it's a quoted string then end is the next unescaped quote
        if (currentChar == '"' || currentChar == '\'') {
            char endChar = currentChar;
            boolean escaped = false;
            start++;
            for (; index < length; index++) {
                if (expr[index] == '\\' && !escaped) {
                    escaped = true;
                    continue;
                }
                if (expr[index] == endChar && !escaped) break;
                escaped = false;
            }
            end = index;
            index++; // Skip the end quote
        } else {
            // End is the next whitespace character
            for (; index < length; index++) {
                if (isMetaChar(expr[index])) break;
            }
            end = index;
        }
        // Extract the string from the array
        this.tokenVal = new String(expr, start, end - start);
        return TOKEN_STRING;
    }


    /**
     * Returns the String value of the token if it was type TOKEN_STRING.
     * Otherwise null is returned.
     */
    public String getTokenValue() {
        return tokenVal;
    }
}