Thanks Dan. Now I have my 15 milliseconds of fame back. ;) I'll see if I can test the updates with my site soon. -Paul Speed
[EMAIL PROTECTED] wrote: > > dsandberg 2002/11/25 02:15:43 > > Modified: catalina/src/share/org/apache/catalina/ssi SSICommand.java > SSIConfig.java SSIEcho.java SSIExec.java > SSIFlastmod.java SSIFsize.java SSIInclude.java > SSIMediator.java SSIPrintenv.java SSIProcessor.java > SSISet.java SSIStopProcessingException.java > tester/src/bin tester.xml > Added: catalina/src/share/org/apache/catalina/ssi > ExpressionParseTree.java ExpressionTokenizer.java > SSIConditional.java SSIConditionalState.java > tester/web SSIConditional09.shtml > tester/web/golden SSIConditional09.txt > Log: > Added back Paul Speed's conditional SSI enhancement. Updated code/regression >tests to better emulate Apache SSI. Fixed bug w/ expression parser's handling of >literals. > > Revision Changes Path > 1.2 +5 -3 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java > > Index: SSICommand.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSICommand.java,v > retrieving revision 1.1 > retrieving revision 1.2 > diff -u -r1.1 -r1.2 > --- SSICommand.java 24 May 2002 16:35:39 -0000 1.1 > +++ SSICommand.java 25 Nov 2002 10:15:42 -0000 1.2 > @@ -79,12 +79,14 @@ > * Write the output of the command to the writer. > * > * @param ssiMediator the ssi mediator > + * @param commandName the name of the actual command ( ie. echo ) > * @param paramNames The parameter names > * @param paramValues The parameter values > * @param writer the writer to output to > * @throws SSIStopProcessingException if SSI processing should be aborted > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) throws SSIStopProcessingException; > > > > 1.3 +6 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java > > Index: SSIConfig.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConfig.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSIConfig.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSIConfig.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -72,6 +72,7 @@ > * Implements the Server-side #exec command > * > * @author Bip Thelin > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -80,6 +81,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer ) { > > > > 1.2 +6 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java > > Index: SSIEcho.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIEcho.java,v > retrieving revision 1.1 > retrieving revision 1.2 > diff -u -r1.1 -r1.2 > --- SSIEcho.java 24 May 2002 04:38:58 -0000 1.1 > +++ SSIEcho.java 25 Nov 2002 10:15:42 -0000 1.2 > @@ -71,6 +71,7 @@ > * Return the result associated with the supplied Server Variable. > * > * @author Bip Thelin > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -82,6 +83,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) { > > > > 1.3 +7 -5 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java > > Index: SSIExec.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIExec.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSIExec.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSIExec.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -89,6 +89,7 @@ > * > * @author Bip Thelin > * @author Amy Roh > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > * > @@ -101,6 +102,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) { > @@ -111,7 +113,7 @@ > String substitutedValue = ssiMediator.substituteVariables( paramValue ); > > if ( paramName.equalsIgnoreCase("cgi") ) { > - ssiInclude.process( ssiMediator, new String[] {"virtual"}, new String[] >{substitutedValue}, writer ); > + ssiInclude.process( ssiMediator, "include", new String[] {"virtual"}, >new String[] {substitutedValue}, writer ); > } else if ( paramName.equalsIgnoreCase("cmd") ) { > boolean foundProgram = false; > try { > > > > 1.3 +6 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java > > Index: SSIFlastmod.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFlastmod.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSIFlastmod.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSIFlastmod.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -75,6 +75,7 @@ > * Implements the Server-side #flastmod command > * > * @author Bip Thelin > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -83,6 +84,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) { > > > > 1.4 +9 -7 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java > > Index: SSIFsize.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIFsize.java,v > retrieving revision 1.3 > retrieving revision 1.4 > diff -u -r1.3 -r1.4 > --- SSIFsize.java 24 Nov 2002 06:22:36 -0000 1.3 > +++ SSIFsize.java 25 Nov 2002 10:15:42 -0000 1.4 > @@ -72,6 +72,7 @@ > * Implements the Server-side #fsize command > * > * @author Bip Thelin > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -83,9 +84,10 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > - String[] paramNames, > - String[] paramValues, > - PrintWriter writer) { > + String commandName, > + String[] paramNames, > + String[] paramValues, > + PrintWriter writer) { > > String configErrMsg = ssiMediator.getConfigErrMsg(); > for(int i=0;i<paramNames.length;i++) { > > > > 1.3 +6 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java > > Index: SSIInclude.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIInclude.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSIInclude.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSIInclude.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -75,6 +75,7 @@ > * Implements the Server-side #include command > * > * @author Bip Thelin > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -83,6 +84,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) { > > > > 1.3 +10 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java > > Index: SSIMediator.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIMediator.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSIMediator.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSIMediator.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -86,6 +86,7 @@ > * > * @author Bip Thelin > * @author Amy Roh > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -102,6 +103,7 @@ > protected Date lastModifiedDate; > protected int debug; > protected Strftime strftime; > + protected SSIConditionalState conditionalState = new SSIConditionalState(); > > static { > //We try to encode only the same characters that apache does > @@ -163,6 +165,10 @@ > > public String getConfigSizeFmt() { > return configSizeFmt; > + } > + > + public SSIConditionalState getConditionalState() { > + return conditionalState; > } > > public Collection getVariableNames() { > > > > 1.2 +5 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java > > Index: SSIPrintenv.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIPrintenv.java,v > retrieving revision 1.1 > retrieving revision 1.2 > diff -u -r1.1 -r1.2 > --- SSIPrintenv.java 24 May 2002 04:38:58 -0000 1.1 > +++ SSIPrintenv.java 25 Nov 2002 10:15:42 -0000 1.2 > @@ -79,6 +79,7 @@ > * @see SSICommand > */ > public void process(SSIMediator ssiMediator, > + String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) { > > > > 1.2 +82 -41 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java > > Index: SSIProcessor.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIProcessor.java,v > retrieving revision 1.1 > retrieving revision 1.2 > diff -u -r1.1 -r1.2 > --- SSIProcessor.java 24 May 2002 04:38:58 -0000 1.1 > +++ SSIProcessor.java 25 Nov 2002 10:15:42 -0000 1.2 > @@ -108,6 +108,11 @@ > addCommand( "fsize", new SSIFsize() ); > addCommand( "printenv", new SSIPrintenv() ); > addCommand( "set", new SSISet() ); > + SSIConditional ssiConditional = new SSIConditional(); > + addCommand( "if", ssiConditional ); > + addCommand( "elif", ssiConditional ); > + addCommand( "endif", ssiConditional ); > + addCommand( "else", ssiConditional ); > } > > public void addCommand( String name, SSICommand command ) { > @@ -147,7 +152,9 @@ > index += COMMAND_START.length(); > command.setLength( 0 ); //clear the command string > } else { > - writer.write( c ); > + if ( >!ssiMediator.getConditionalState().processConditionalCommandsOnly ) { > + writer.write( c ); > + } > index++; > } > } else { > @@ -159,20 +166,29 @@ > ssiExternalResolver.log( "SSIProcessor.process -- >processing command: " + strCmd, null ); > } > String[] paramNames = parseParamNames(command, >strCmd.length()); > - String[] paramValues = parseParamValues(command, >strCmd.length()); > + String[] paramValues = parseParamValues(command, >strCmd.length(), paramNames.length ); > > //We need to fetch this value each time, since it may change >during the loop > String configErrMsg = ssiMediator.getConfigErrMsg(); > SSICommand ssiCommand = (SSICommand) >commands.get(strCmd.toLowerCase()); > - if ( ssiCommand != null ) { > - if ( paramNames.length==paramValues.length ) { > - ssiCommand.process( ssiMediator, paramNames, >paramValues, writer ); > - } else { > - ssiExternalResolver.log( "Parameter names count does >not match parameter values count on command: " + strCmd, null ); > - writer.write( configErrMsg ); > - } > + String errorMessage = null; > + if ( ssiCommand == null ) { > + errorMessage = "Unknown command: " + strCmd; > + } else if ( paramValues == null ) { > + errorMessage = "Error parsing directive parameters."; > + } else if ( paramNames.length!=paramValues.length ) { > + errorMessage = "Parameter names count does not match >parameter values count on command: " + strCmd; > } else { > - ssiExternalResolver.log( "Unknown command: " + strCmd, >null); > + // don't process the command if we are processing >conditional commands only and the > + // command is not conditional > + if ( >!ssiMediator.getConditionalState().processConditionalCommandsOnly || > + ssiCommand instanceof SSIConditional ) { > + ssiCommand.process( ssiMediator, strCmd, paramNames, >paramValues, writer ); > + } > + } > + > + if ( errorMessage != null ) { > + ssiExternalResolver.log( errorMessage, null ); > writer.write( configErrMsg ); > } > } else { > @@ -214,20 +230,29 @@ > bIdx++; > } > > - retBuf.append('"'); > + retBuf.append('='); > inside=!inside; > quotes=0; > > - while(bIdx < cmd.length()&"es!=2) { > - if(cmd.charAt(bIdx)=='"') > - quotes++; > + boolean escaped=false; > + for ( ; bIdx < cmd.length() && quotes != 2; bIdx++ ) { > + char c = cmd.charAt(bIdx); > + > + // Need to skip escaped characters > + if (c=='\\' && !escaped) { > + escaped = true; > + bIdx++; > + continue; > + } > + escaped = false; > > - bIdx++; > + if (c=='"') > + quotes++; > } > } > } > > - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\""); > + StringTokenizer str = new StringTokenizer(retBuf.toString(), "="); > String[] retString = new String[str.countTokens()]; > > while(str.hasMoreTokens()) { > @@ -243,15 +268,14 @@ > * @param cmd a value of type 'StringBuffer' > * @return a value of type 'String[]' > */ > - protected String[] parseParamValues(StringBuffer cmd, int start) { > - int bIdx = start; > - int i = 0; > - int quotes = 0; > + protected String[] parseParamValues(StringBuffer cmd, int start, int count) { > + int valIndex = 0; > boolean inside = false; > - StringBuffer retBuf = new StringBuffer(); > + String[] vals = new String[count]; > + StringBuffer sb = new StringBuffer(); > > - while(bIdx < cmd.length()) { > - if(!inside) { > + for (int bIdx = start; bIdx < cmd.length(); bIdx++ ) { > + if (!inside) { > while(bIdx < cmd.length()&& > cmd.charAt(bIdx)!='"') > bIdx++; > @@ -261,26 +285,43 @@ > > inside=!inside; > } else { > - while(bIdx < cmd.length() && cmd.charAt(bIdx)!='"') { > - retBuf.append(cmd.charAt(bIdx)); > - bIdx++; > - } > + boolean escaped=false; > + for ( ; bIdx < cmd.length(); bIdx++) { > > - retBuf.append('"'); > - inside=!inside; > - } > + char c = cmd.charAt(bIdx); > > - bIdx++; > - } > + // Check for escapes > + if (c=='\\' && !escaped) { > + escaped = true; > + continue; > + } > + > + // If we reach the other " then stop > + if (c=='"' && !escaped) > + break; > + > + // Since parsing of attributes and var > + // substitution is done in separate places, > + // we need to leave escape in the string > + if (c=='$' && escaped) > + sb.append( '\\' ); > > - StringTokenizer str = new StringTokenizer(retBuf.toString(), "\""); > - String[] retString = new String[str.countTokens()]; > + escaped = false; > + sb.append(c); > + } > > - while(str.hasMoreTokens()) { > - retString[i++] = str.nextToken(); > + // If we hit the end without seeing a quote > + // the signal an error > + if (bIdx == cmd.length()) > + return null; > + > + vals[valIndex++] = sb.toString(); > + sb.delete( 0, sb.length() ); // clear the buffer > + inside=!inside; > + } > } > > - return retString; > + return vals; > } > > /** > > > > 1.3 +10 -8 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java > > Index: SSISet.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSISet.java,v > retrieving revision 1.2 > retrieving revision 1.3 > diff -u -r1.2 -r1.3 > --- SSISet.java 24 Nov 2002 06:22:36 -0000 1.2 > +++ SSISet.java 25 Nov 2002 10:15:42 -0000 1.3 > @@ -70,6 +70,7 @@ > /** > * Implements the Server-side #set command > * > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > @@ -77,10 +78,11 @@ > /** > * @see SSICommand > */ > - public void process(SSIMediator ssiMediator, > - String[] paramNames, > - String[] paramValues, > - PrintWriter writer) throws SSIStopProcessingException { > + public void process( SSIMediator ssiMediator, > + String commandName, > + String[] paramNames, > + String[] paramValues, > + PrintWriter writer) throws SSIStopProcessingException { > > String errorMessage = ssiMediator.getConfigErrMsg(); > String variableName = null; > > > > 1.2 +5 -4 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java > > Index: SSIStopProcessingException.java > =================================================================== > RCS file: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIStopProcessingException.java,v > retrieving revision 1.1 > retrieving revision 1.2 > diff -u -r1.1 -r1.2 > --- SSIStopProcessingException.java 24 May 2002 04:38:58 -0000 1.1 > +++ SSIStopProcessingException.java 25 Nov 2002 10:15:42 -0000 1.2 > @@ -67,6 +67,7 @@ > * Exception used to tell SSIProcessor that it should stop processing SSI >commands. > * This is used to mimick the Apache behavior in #set with invalid attributes. > * > + * @author Paul Speed > * @author Dan Sandberg > * @version $Revision$, $Date$ > */ > > > > 1.1 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java > > Index: ExpressionParseTree.java > =================================================================== > /* > * ExpressionParseTree.java > * $Header: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionParseTree.java,v > 1.1 2002/11/25 10:15:42 dsandberg Exp $ > * $Revision: 1.1 $ > * $Date: 2002/11/25 10:15:42 $ > * > * ==================================================================== > * > * The Apache Software License, Version 1.1 > * > * Copyright (c) 1999 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowlegement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowlegement may appear in the software itself, > * if and wherever such third-party acknowlegements normally appear. > * > * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact [EMAIL PROTECTED] > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Group. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. > * > * [Additional notices, if required by prior licensing conditions] > * > */ > > package org.apache.catalina.ssi; > > import java.util.LinkedList; > import java.util.List; > import java.text.ParseException; > > /** > * Represents a parsed expression. > * > * @version $Revision: 1.1 $ > * @author Paul Speed > */ > public class ExpressionParseTree > { > /** > * Contains the current set of completed nodes. This > * is a workspace for the parser. > */ > private LinkedList nodeStack = new LinkedList(); > > /** > * Contains operator nodes that don't yet have values. > * This is a workspace for the parser. > */ > private LinkedList oppStack = new LinkedList(); > > /** > * The root node after the expression has been parsed. > */ > private Node root; > > /** > * The SSIMediator to use when evaluating the expressions. > */ > private SSIMediator ssiMediator; > > /** > * Creates a new parse tree for the specified expression. > */ > public ExpressionParseTree( String expr, > SSIMediator ssiMediator ) > throws ParseException { > this.ssiMediator = ssiMediator; > parseExpression( expr ); > } > > /** > * Evaluates the tree and returns true or false. The specified > * SSIMediator is used to resolve variable references. > */ > public boolean evaluateTree() { > return root.evaluate(); > } > > /** > * Pushes a new operator onto the opp stack, resolving existing > * opps as needed. > */ > private void pushOpp( OppNode node ) { > > // If node is null then it's just a group marker > if( node == null ) { > oppStack.add( 0, node ); > return; > } > > while (true) { > if (oppStack.size() == 0) > break; > OppNode top = (OppNode)oppStack.get(0); > > // If the top is a spacer then don't pop > // anything > if (top == null) > break; > > // If the top node has a lower precedence then > // let it stay > if (top.getPrecedence() < node.getPrecedence()) > break; > > // Remove the top node > oppStack.remove(0); > > // Let it fill its branches > top.popValues( nodeStack ); > > // Stick it on the resolved node stack > nodeStack.add( 0, top ); > } > > // Add the new node to the opp stack > oppStack.add( 0, node ); > } > > /** > * Resolves all pending opp nodes on the stack until the > * next group marker is reached. > */ > private void resolveGroup() { > > OppNode top = null; > while ((top=(OppNode)oppStack.remove(0)) != null ) { > // Let it fill its branches > top.popValues( nodeStack ); > > // Stick it on the resolved node stack > nodeStack.add( 0, top ); > } > } > > /** > * Parses the specified expression into a tree of > * parse nodes. > */ > private void parseExpression( String expr ) throws ParseException { > > StringNode currStringNode = null; > > // We cheat a little and start an artificial > // group right away. It makes finishing easier. > pushOpp( null ); > > ExpressionTokenizer et = new ExpressionTokenizer(expr); > while (et.hasMoreTokens()) { > int token = et.nextToken(); > > if (token != ExpressionTokenizer.TOKEN_STRING) > currStringNode = null; > > switch (token) { > case ExpressionTokenizer.TOKEN_STRING: > if (currStringNode == null) { > currStringNode = new StringNode( et.getTokenValue() ); > nodeStack.add( 0, currStringNode ); > } else { > // Add to the existing > currStringNode.value.append( " " ); > currStringNode.value.append( et.getTokenValue() ); > } > break; > case ExpressionTokenizer.TOKEN_AND: > pushOpp( new AndNode() ); > break; > case ExpressionTokenizer.TOKEN_OR: > pushOpp( new OrNode() ); > break; > case ExpressionTokenizer.TOKEN_NOT: > pushOpp( new NotNode() ); > break; > case ExpressionTokenizer.TOKEN_EQ: > pushOpp( new EqualNode() ); > break; > case ExpressionTokenizer.TOKEN_NOT_EQ: > pushOpp( new NotNode() ); > // Sneak the regular node in. The NOT will > // be resolved when the next opp comes along. > oppStack.add( 0, new EqualNode() ); > break; > case ExpressionTokenizer.TOKEN_RBRACE: > // Closeout the current group > resolveGroup(); > break; > case ExpressionTokenizer.TOKEN_LBRACE: > // Push a group marker > pushOpp( null ); > break; > case ExpressionTokenizer.TOKEN_GE: > pushOpp( new NotNode() ); > // Similar stategy to NOT_EQ above, except this > // is NOT less than > oppStack.add( 0, new LessThanNode() ); > break; > case ExpressionTokenizer.TOKEN_LE: > pushOpp( new NotNode() ); > // Similar stategy to NOT_EQ above, except this > // is NOT greater than > oppStack.add( 0, new GreaterThanNode() ); > break; > case ExpressionTokenizer.TOKEN_GT: > pushOpp( new GreaterThanNode() ); > break; > case ExpressionTokenizer.TOKEN_LT: > pushOpp( new LessThanNode() ); > break; > case ExpressionTokenizer.TOKEN_END: > break; > } > } > > // Finish off the rest of the opps > resolveGroup(); > > if (nodeStack.size() == 0) { > throw new ParseException( "No nodes created.", > et.getIndex() ); > } > if (nodeStack.size() > 1) { > throw new ParseException( "Extra nodes created.", > et.getIndex() ); > } > if (oppStack.size() != 0) { > throw new ParseException( "Unused opp nodes exist.", > et.getIndex() ); > } > > root = (Node)nodeStack.get(0); > } > > /** > * A node in the expression parse tree. > */ > private abstract class Node { > > /** > * Return true if the node evaluates to true. > */ > public abstract boolean evaluate(); > } > > /** > * A node the represents a String value > */ > private class StringNode extends Node { > > StringBuffer value; > String resolved = null; > > public StringNode( String value ) { > this.value = new StringBuffer(value); > } > > /** > * Resolves any variable references and returns the > * value string. > */ > public String getValue() { > if (resolved == null) > resolved = ssiMediator.substituteVariables( value.toString() ) ; > return resolved; > } > > /** > * Returns true if the string is not empty. > */ > public boolean evaluate() { > return !(getValue().length() == 0); > } > > public String toString() { > return value.toString(); > } > } > > private static final int PRECEDENCE_NOT = 5; > private static final int PRECEDENCE_COMPARE = 4; > private static final int PRECEDENCE_LOGICAL = 1; > > /** > * A node implementation that represents an operation. > */ > private abstract class OppNode extends Node { > > /** > * The left branch. > */ > Node left; > > /** > * The right branch. > */ > Node right; > > /** > * Returns a preference level suitable for comparison to > * other OppNode preference levels. > */ > public abstract int getPrecedence(); > > /** > * Lets the node pop its own branch nodes off the front of > * the specified list. The default pulls two. > */ > public void popValues( List values ) { > right = (Node)values.remove(0); > left = (Node)values.remove(0); > } > } > > private final class NotNode extends OppNode { > > public boolean evaluate() { > return !left.evaluate(); > } > > public int getPrecedence() { > return PRECEDENCE_NOT; > } > > /** > * Overridden to pop only one value. > */ > public void popValues( List values ) { > left = (Node)values.remove(0); > } > > public String toString() { > return left + " NOT"; > } > } > > private final class AndNode extends OppNode { > > public boolean evaluate() { > if (!left.evaluate()) // Short circuit > return false; > return right.evaluate(); > } > > public int getPrecedence() { > return PRECEDENCE_LOGICAL; > } > > public String toString() { > return left + " " + right + " AND"; > } > } > > private final class OrNode extends OppNode { > > public boolean evaluate() { > if (left.evaluate()) // Short circuit > return true; > return right.evaluate(); > } > > public int getPrecedence() { > return PRECEDENCE_LOGICAL; > } > > public String toString() { > return left + " " + right + " OR"; > } > } > > private abstract class CompareNode extends OppNode { > protected int compareBranches() { > String val1 = ((StringNode)left).getValue(); > String val2 = ((StringNode)right).getValue(); > return val1.compareTo(val2); > } > } > > private final class EqualNode extends CompareNode { > > public boolean evaluate() { > return (compareBranches() == 0); > } > > public int getPrecedence() { > return PRECEDENCE_COMPARE; > } > > public String toString() { > return left + " " + right + " EQ"; > } > } > > private final class GreaterThanNode extends CompareNode { > > public boolean evaluate() { > return (compareBranches() > 0); > } > > public int getPrecedence() { > return PRECEDENCE_COMPARE; > } > > public String toString() { > return left + " " + right + " GT"; > } > } > > private final class LessThanNode extends CompareNode { > > public boolean evaluate() { > return (compareBranches() < 0); > } > > public int getPrecedence() { > return PRECEDENCE_COMPARE; > } > > public String toString() { > return left + " " + right + " LT"; > } > } > } > > > > 1.1 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java > > Index: ExpressionTokenizer.java > =================================================================== > /* > * ExpressionTokenizer.java > * $Header: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/ExpressionTokenizer.java,v > 1.1 2002/11/25 10:15:42 dsandberg Exp $ > * $Revision: 1.1 $ > * $Date: 2002/11/25 10:15:42 $ > * > * ==================================================================== > * > * The Apache Software License, Version 1.1 > * > * Copyright (c) 1999 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowlegement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowlegement may appear in the software itself, > * if and wherever such third-party acknowlegements normally appear. > * > * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact [EMAIL PROTECTED] > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Group. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. > * > * [Additional notices, if required by prior licensing conditions] > * > */ > > 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.1 $ > * @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 int tokenType = TOKEN_STRING; > 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; > } > } > > > > 1.1 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java > > Index: SSIConditional.java > =================================================================== > /* > * SSIConditional.java > * $Header: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditional.java,v > 1.1 2002/11/25 10:15:42 dsandberg Exp $ > * $Revision: 1.1 $ > * $Date: 2002/11/25 10:15:42 $ > * > * ==================================================================== > * > * The Apache Software License, Version 1.1 > * > * Copyright (c) 1999 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowlegement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowlegement may appear in the software itself, > * if and wherever such third-party acknowlegements normally appear. > * > * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact [EMAIL PROTECTED] > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Group. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. > * > * [Additional notices, if required by prior licensing conditions] > * > */ > > package org.apache.catalina.ssi; > > import java.io.PrintWriter; > import java.text.ParseException; > import java.util.LinkedList; > import java.util.List; > > import javax.servlet.ServletOutputStream; > > /** > * SSI command that handles all conditional directives. > * > * @version $Revision: 1.1 $ > * @author Paul Speed > */ > public class SSIConditional implements SSICommand { > /** > * @see SSICommand > */ > public void process( SSIMediator ssiMediator, > String commandName, > String[] paramNames, > String[] paramValues, > PrintWriter writer) throws SSIStopProcessingException { > > // Retrieve the current state information > SSIConditionalState state = ssiMediator.getConditionalState(); > > if ( "if".equalsIgnoreCase( commandName ) ) { > // Do nothing if we are nested in a false branch > // except count it > if ( state.processConditionalCommandsOnly ) { > state.nestingCount++; > return; > } > > state.nestingCount = 0; > > // Evaluate the expression > if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) { > // No more branches can be taken for this if block > state.branchTaken = true; > } else { > // Do not process this branch > state.processConditionalCommandsOnly = true; > state.branchTaken = false; > } > > } else if ( "elif".equalsIgnoreCase( commandName ) ) { > // No need to even execute if we are nested in > // a false branch > if (state.nestingCount > 0) > return; > > // If a branch was already taken in this if block > // then disable output and return > if ( state.branchTaken ) { > state.processConditionalCommandsOnly = true; > return; > } > > // Evaluate the expression > if ( evaluateArguments(paramNames, paramValues, ssiMediator) ) { > // Turn back on output and mark the branch > state.processConditionalCommandsOnly = false; > state.branchTaken = true; > } else { > // Do not process this branch > state.processConditionalCommandsOnly = true; > state.branchTaken = false; > } > > } else if ( "else".equalsIgnoreCase( commandName ) ) { > // No need to even execute if we are nested in > // a false branch > if (state.nestingCount > 0) > return; > > // If we've already taken another branch then > // disable output otherwise enable it. > state.processConditionalCommandsOnly = state.branchTaken; > > // And in any case, it's safe to say a branch > // has been taken. > state.branchTaken = true; > > } else if ( "endif".equalsIgnoreCase( commandName ) ) { > // If we are nested inside a false branch then pop out > // one level on the nesting count > if (state.nestingCount > 0) { > state.nestingCount--; > return; > } > > // Turn output back on > state.processConditionalCommandsOnly = false; > > // Reset the branch status for any outer if blocks, > // since clearly we took a branch to have gotten here > // in the first place. > state.branchTaken = true; > } else { > throw new SSIStopProcessingException(); > //throw new SsiCommandException( "Not a conditional command:" + >cmdName ); > } > } > > /** > * Retrieves the expression from the specified arguments > * and peforms the necessary evaluation steps. > */ > private boolean evaluateArguments( String[] names, > String[] values, > SSIMediator ssiMediator ) throws >SSIStopProcessingException { > String expr = getExpression( names, values ); > if (expr == null) { > throw new SSIStopProcessingException(); > //throw new SsiCommandException( "No expression specified." ); > } > > try { > ExpressionParseTree tree = new ExpressionParseTree( expr, > ssiMediator ); > return tree.evaluateTree(); > } catch (ParseException e) { > //throw new SsiCommandException( "Error parsing expression." ); > throw new SSIStopProcessingException(); > } > } > > /** > * Returns the "expr" if the arg name is appropriate, otherwise > * returns null. > */ > private String getExpression( String[] paramNames, String[] paramValues ) { > if ( "expr".equalsIgnoreCase( paramNames[0]) ) > return paramValues[0]; > return null; > } > } > > > > 1.1 >jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java > > Index: SSIConditionalState.java > =================================================================== > /* > * SSIConditionalState.java > * $Header: >/home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/ssi/SSIConditionalState.java,v > 1.1 2002/11/25 10:15:42 dsandberg Exp $ > * $Revision: 1.1 $ > * $Date: 2002/11/25 10:15:42 $ > * > * ==================================================================== > * > * The Apache Software License, Version 1.1 > * > * Copyright (c) 1999 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowlegement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowlegement may appear in the software itself, > * if and wherever such third-party acknowlegements normally appear. > * > * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact [EMAIL PROTECTED] > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Group. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. > * > * [Additional notices, if required by prior licensing conditions] > * > */ > > package org.apache.catalina.ssi; > > /** > * This class is used by SSIMediator and SSIConditional to keep track of state >information necessary to process > * the nested conditional commands ( if, elif, else, endif ). > * > * @version $Revision: 1.1 $ > * @author Dan Sandberg > * @author Paul Speed > */ > class SSIConditionalState { > /** > * Set to true if the current conditional has already been > * completed, i.e.: a branch was taken. > */ > boolean branchTaken = false; > > /** > * Counts the number of nested false branches. > */ > int nestingCount = 0; > > /** > * Set to true if only conditional commands ( if, elif, else, endif ) should >be processed. > */ > boolean processConditionalCommandsOnly = false; > } > > > > 1.85 +36 -0 jakarta-tomcat-4.0/tester/src/bin/tester.xml > > Index: tester.xml > =================================================================== > RCS file: /home/cvs/jakarta-tomcat-4.0/tester/src/bin/tester.xml,v > retrieving revision 1.84 > retrieving revision 1.85 > diff -u -r1.84 -r1.85 > --- tester.xml 24 Nov 2002 06:22:36 -0000 1.84 > +++ tester.xml 25 Nov 2002 10:15:43 -0000 1.85 > @@ -1849,6 +1849,42 @@ > golden="${golden.path}/SSIFsize02.txt"/> > > <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional01.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional01.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional02.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional02.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional03.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional03.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional04.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional04.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional05.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional05.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional06.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional06.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional07.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional07.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional08.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional08.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > + request="${context.path}/SSIConditional09.shtml" debug="${debug}" > + golden="${golden.path}/SSIConditional09.txt"/> > + > + <tester host="${host}" port="${port}" protocol="${protocol}" > request="${context.path}/SSIVarSub01.shtml" debug="${debug}" > golden="${golden.path}/SSIVarSub01.txt"/> > > > > > 1.1 jakarta-tomcat-4.0/tester/web/SSIConditional09.shtml > > Index: SSIConditional09.shtml > =================================================================== > 1 > <!--#if expr="1=2" --> > a > ##<!--#if expr="1=2" --> > b > ##<!--#else --> > c > ##<!--#endif --> > d > <!--#elif expr="2=2" --> > e > ##<!--#if expr="2=2" --> > f > ####<!--#if expr="1=2" --> > **11 > ####<!--#elif expr="2=3" --> > **22 > ####<!--#endif --> > **33 > ##<!--#else --> > g > ##<!--#endif --> > h > <!--#else --> > i > ##<!--#if expr="1=1" --> > j > ##<!--#else --> > k > ##<!--#endif --> > l > <!--#endif --> > # > now we test extra #endif commands > <!--#endif --> > n > <!--#endif --> > o > > > 1.1 jakarta-tomcat-4.0/tester/web/golden/SSIConditional09.txt > > Index: SSIConditional09.txt > =================================================================== > 1 > > e > ## > f > #### > **33 > ## > h > > # > now we test extra #endif commands > > n > > o > > > > -- > To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> > For additional commands, e-mail: <mailto:[EMAIL PROTECTED]> -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>