Thread: [Adapdev-commits] Adapdev/src/Adapdev.NVelocity/Runtime/Directive Directive.cs,1.4,1.5 DirectiveCons
Status: Beta
Brought to you by:
intesar66
From: Sean M. <int...@us...> - 2005-11-16 07:02:00
|
Update of /cvsroot/adapdev/Adapdev/src/Adapdev.NVelocity/Runtime/Directive In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv909/src/Adapdev.NVelocity/Runtime/Directive Added Files: Directive.cs DirectiveConstants.cs Foreach.cs Include.cs Literal.cs Macro.cs Parse.cs ParseDirectiveException.cs VMProxyArg.cs VelocimacroProxy.cs Log Message: --- NEW FILE: Directive.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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/>. */ using System; using System.IO; using NVelocity.Context; using NVelocity.Runtime.Parser.Node; /// <summary> Base class for all directives used in Velocity. /// * /// </summary> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a> /// </author> /// <version> $Id: Directive.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ /// /// </version> public abstract class Directive : DirectiveConstants //,System.ICloneable { public abstract String Name { get; set; } public abstract int Type { get; } public virtual int Line { get { return line; } } public virtual int Column { get { return column; } } private int line = 0; private int column = 0; protected internal RuntimeServices rsvc = null; /// <summary>Return the name of this directive /// </summary> /// <summary>Get the directive type BLOCK/LINE /// </summary> /// <summary>Allows the template location to be set /// </summary> public virtual void setLocation(int line, int column) { this.line = line; this.column = column; } /// <summary>for log msg purposes /// </summary> /// <summary>for log msg purposes /// </summary> /// <summary> How this directive is to be initialized. /// </summary> public virtual void init(RuntimeServices rs, InternalContextAdapter context, INode node) { rsvc = rs; // int i, k = node.jjtGetNumChildren(); //for (i = 0; i < k; i++) // node.jjtGetChild(i).init(context, rs); } /// <summary> How this directive is to be rendered /// </summary> public abstract bool render(InternalContextAdapter context, TextWriter writer, INode node); } } --- NEW FILE: VelocimacroProxy.cs --- namespace NVelocity.Runtime.Directive { using System; using System.Collections; using System.IO; using NVelocity.Context; using NVelocity.Exception; using NVelocity.Runtime.Parser; using NVelocity.Runtime.Parser.Node; using NVelocity.Runtime.Visitor; using NVelocity.Util; /// <summary> /// VelocimacroProxy.java /// a proxy Directive-derived object to fit with the current directive system /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a></author> /// <version> $Id: VelocimacroProxy.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ </version> public class VelocimacroProxy : Directive { public VelocimacroProxy() { InitBlock(); } private void InitBlock() { proxyArgHash = new Hashtable(); } public override String Name { get { return macroName; } set { macroName = value; } } public override int Type { get { return DirectiveConstants_Fields.LINE; } } public virtual String[] ArgArray { set { argArray = value; /* * get the arg count from the arg array. remember that the arg array * has the macro name as it's 0th element */ numMacroArgs = argArray.Length - 1; } } public virtual SimpleNode NodeTree { set { nodeTree = value; } } public virtual int NumArgs { get { return numMacroArgs; } } public virtual String Macrobody { set { macroBody = value; } } public virtual String Namespace { set { this.namespace_Renamed = value; } } private String macroName = ""; private String macroBody = ""; private String[] argArray = null; private SimpleNode nodeTree = null; private int numMacroArgs = 0; private String namespace_Renamed = ""; //UPGRADE_NOTE: Field init was renamed. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1029"' private bool init_Renamed_Field = false; private String[] callingArgs; private int[] callingArgTypes; //UPGRADE_NOTE: The initialization of 'proxyArgHash' was moved to method 'InitBlock'. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1005"' private Hashtable proxyArgHash; /// <summary> Return name of this Velocimacro. /// </summary> /// <summary> Velocimacros are always LINE /// type directives. /// </summary> /// <summary> sets the directive name of this VM /// </summary> /// <summary> sets the array of arguments specified in the macro definition /// </summary> /// <summary> returns the number of ars needed for this VM /// </summary> /// <summary> Sets the orignal macro body. This is simply the cat of the macroArray, but the /// Macro object creates this once during parsing, and everyone shares it. /// Note : it must not be modified. /// </summary> /// <summary> Renders the macro using the context /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, INode node) { try { /* * it's possible the tree hasn't been parsed yet, so get * the VMManager to parse and init it */ if (nodeTree != null) { if (!init_Renamed_Field) { nodeTree.init(context, rsvc); init_Renamed_Field = true; } /* * wrap the current context and add the VMProxyArg objects */ VMContext vmc = new VMContext(context, rsvc); for (int i = 1; i < argArray.Length; i++) { /* * we can do this as VMProxyArgs don't change state. They change * the context. */ VMProxyArg arg = (VMProxyArg) proxyArgHash[argArray[i]]; vmc.AddVMProxyArg(arg); } /* * now render the VM */ nodeTree.render(vmc, writer); } else { rsvc.error("VM error : " + macroName + ". Null AST"); } } catch (Exception e) { /* * if it's a MIE, it came from the render.... throw it... */ if (e is MethodInvocationException) { throw (MethodInvocationException) e; } rsvc.error("VelocimacroProxy.render() : exception VM = #" + macroName + "() : " + StringUtils.stackTrace(e)); } return true; } /// <summary> The major meat of VelocimacroProxy, init() checks the # of arguments, patches the /// macro body, renders the macro into an AST, and then inits the AST, so it is ready /// for quick rendering. Note that this is only AST dependant stuff. Not context. /// </summary> public override void init(RuntimeServices rs, InternalContextAdapter context, INode node) { base.init(rs, context, node); /* * how many args did we get? */ int i = node.jjtGetNumChildren(); /* * right number of args? */ if (NumArgs != i) { rsvc.error("VM #" + macroName + ": error : too " + ((NumArgs > i) ? "few" : "many") + " arguments to macro. Wanted " + NumArgs + " got " + i); return; } /* * get the argument list to the instance use of the VM */ callingArgs = getArgArray(node); /* * now proxy each arg in the context */ setupMacro(callingArgs, callingArgTypes); return; } /// <summary> /// basic VM setup. Sets up the proxy args for this /// use, and parses the tree /// </summary> public virtual bool setupMacro(String[] callArgs, int[] callArgTypes) { setupProxyArgs(callArgs, callArgTypes); parseTree(callArgs); return true; } /// <summary> /// parses the macro. We need to do this here, at init time, or else /// the local-scope template feature is hard to get to work :) /// </summary> private void parseTree(String[] callArgs) { try { //UPGRADE_ISSUE: The equivalent of constructor 'java.io.BufferedReader.BufferedReader' is incompatible with the expected type in C#. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1109"' TextReader br = new StringReader(macroBody); /* * now parse the macro - and don't dump the namespace */ nodeTree = rsvc.parse(br, namespace_Renamed, false); /* * now, to make null references render as proper schmoo * we need to tweak the tree and change the literal of * the appropriate references * * we only do this at init time, so it's the overhead * is irrelevant */ Hashtable hm = new Hashtable(); for (int i = 1; i < argArray.Length; i++) { String arg = callArgs[i - 1]; /* * if the calling arg is indeed a reference * then we add to the map. We ignore other * stuff */ if (arg[0] == '$') { hm[argArray[i]] = arg; } } /* * now make one of our reference-munging visitor, and * let 'er rip */ VMReferenceMungeVisitor v = new VMReferenceMungeVisitor(hm); nodeTree.jjtAccept(v, null); } catch (Exception e) { rsvc.error("VelocimacroManager.parseTree() : exception " + macroName + " : " + StringUtils.stackTrace(e)); } } private void setupProxyArgs(String[] callArgs, int[] callArgTypes) { /* * for each of the args, make a ProxyArg */ for (int i = 1; i < argArray.Length; i++) { VMProxyArg arg = new VMProxyArg(rsvc, argArray[i], callArgs[i - 1], callArgTypes[i - 1]); proxyArgHash[argArray[i]] = arg; } } /// <summary> gets the args to the VM from the instance-use AST /// </summary> private String[] getArgArray(INode node) { int numArgs = node.jjtGetNumChildren(); String[] args = new String[numArgs]; callingArgTypes = new int[numArgs]; /* * eat the args */ int i = 0; Token t = null; Token tLast = null; while (i < numArgs) { args[i] = ""; /* * we want string literalss to lose the quotes. #foo( "blargh" ) should have 'blargh' patched * into macro body. So for each arg in the use-instance, treat the stringlierals specially... */ callingArgTypes[i] = node.jjtGetChild(i).Type; if (false && node.jjtGetChild(i).Type == ParserTreeConstants.JJTSTRINGLITERAL) { args[i] += node.jjtGetChild(i).FirstToken.image.Substring(1, (node.jjtGetChild(i).FirstToken.image.Length - 1) - (1)); } else { /* * just wander down the token list, concatenating everything together */ t = node.jjtGetChild(i).FirstToken; tLast = node.jjtGetChild(i).LastToken; while (t != tLast) { args[i] += t.image; t = t.next; } /* * don't forget the last one... :) */ args[i] += t.image; } i++; } return args; } } } --- NEW FILE: Literal.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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/>. */ using System; using System.IO; using NVelocity.Context; using NVelocity.Runtime.Parser.Node; /// <summary> A very simple directive that leverages the Node.literal() /// to grab the literal rendition of a node. We basically /// grab the literal value on init(), then repeatedly use /// that during render(). /// * /// </summary> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a> /// </author> /// <version> $Id: Literal.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ /// /// </version> public class Literal : Directive { public override String Name { get { return "literal"; } set { throw new NotSupportedException(); } } public override int Type { get { return DirectiveConstants_Fields.BLOCK; } } internal String literalText; /// <summary> Return name of this directive. /// </summary> /// <summary> Return type of this directive. /// </summary> /// <summary> Store the literal rendition of a node using /// the Node.literal(). /// </summary> public override void init(RuntimeServices rs, InternalContextAdapter context, INode node) { base.init(rs, context, node); literalText = node.jjtGetChild(0).literal(); } /// <summary> Throw the literal rendition of the block between /// #literal()/#end into the writer. /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, INode node) { writer.Write(literalText); return true; } } } --- NEW FILE: Parse.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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/>. */ using System; using System.IO; using System.Text; using NVelocity.Context; using NVelocity.Exception; using NVelocity.Runtime.Parser.Node; using NVelocity.Runtime.Resource; using Node = Parser.Node.INode; /// <summary> Pluggable directive that handles the #parse() statement in VTL. /// * /// Notes: /// ----- /// 1) The parsed source material can only come from somewhere in /// the TemplateRoot tree for security reasons. There is no way /// around this. If you want to include content from elsewhere on /// your disk, use a link from somwhere under Template Root to that /// content. /// * /// 2) There is a limited parse depth. It is set as a property /// "parse_directive.maxdepth = 10" for example. There is a 20 iteration /// safety in the event that the parameter isn't set. /// * /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a> /// </author> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a> /// </author> /// <author> <a href="mailto:Chr...@dl...">Christoph Reck</a> /// </author> /// <version> $Id: Parse.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ /// /// </version> public class Parse : Directive { public override String Name { get { return "parse"; } set { throw new NotSupportedException(); } } public override int Type { get { return DirectiveConstants_Fields.LINE; } } private bool ready = false; /// <summary> Return name of this directive. /// </summary> /// <summary> Return type of this directive. /// </summary> /// <summary> iterates through the argument list and renders every /// argument that is appropriate. Any non appropriate /// arguments are logged, but render() continues. /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, Node node) { /* * did we get an argument? */ if (node.jjtGetChild(0) == null) { rsvc.error("#parse() error : null argument"); return false; } /* * does it have a value? If you have a null reference, then no. */ Object value_Renamed = node.jjtGetChild(0).value_Renamed(context); if (value_Renamed == null) { rsvc.error("#parse() error : null argument"); return false; } /* * get the path */ //UPGRADE_TODO: The equivalent in .NET for method 'java.Object.toString' may return a different value. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1043"' String arg = value_Renamed.ToString(); /* * see if we have exceeded the configured depth. * If it isn't configured, put a stop at 20 just in case. */ Object[] templateStack = context.TemplateNameStack; if (templateStack.Length >= rsvc.getInt(RuntimeConstants_Fields.PARSE_DIRECTIVE_MAXDEPTH, 20)) { StringBuilder path = new StringBuilder(); for (int i = 0; i < templateStack.Length; ++i) { path.Append(" > " + templateStack[i]); } rsvc.error("Max recursion depth reached (" + templateStack.Length + ")" + " File stack:" + path); return false; } Resource current = context.CurrentResource; /* * get the resource, and assume that we use the encoding of the current template * the 'current resource' can be null if we are processing a stream.... */ String encoding = null; if (current != null) { encoding = current.Encoding; } else { encoding = (String) rsvc.getProperty(RuntimeConstants_Fields.INPUT_ENCODING); } /* * now use the Runtime resource loader to get the template */ Template t = null; try { FileInfo f = new FileInfo(context.CurrentTemplateName); string directory = f.DirectoryName; if(arg.IndexOf("\\") < 0) arg = Path.Combine(directory, arg); t = rsvc.getTemplate(arg, encoding); } catch (ResourceNotFoundException rnfe) { /* * the arg wasn't found. Note it and throw */ rsvc.error("#parse(): cannot find template '" + arg + "', called from template " + context.CurrentTemplateName + " at (" + Line + ", " + Column + ")"); throw rnfe; } catch (ParseErrorException pee) { /* * the arg was found, but didn't parse - syntax error * note it and throw */ rsvc.error("#parse(): syntax error in #parse()-ed template '" + arg + "', called from template " + context.CurrentTemplateName + " at (" + Line + ", " + Column + ")"); throw pee; } catch (Exception e) { rsvc.error("#parse() : arg = " + arg + ". Exception : " + e); return false; } /* * and render it */ try { context.PushCurrentTemplateName(arg); ((SimpleNode) t.Data).render(context, writer); } catch (Exception e) { /* * if it's a MIE, it came from the render.... throw it... */ if (e is MethodInvocationException) { throw (MethodInvocationException) e; } rsvc.error("Exception rendering #parse( " + arg + " ) : " + e); return false; } finally { context.PopCurrentTemplateName(); } return true; } } } --- NEW FILE: Macro.cs --- using Node = NVelocity.Runtime.Parser.Node.INode; namespace NVelocity.Runtime.Directive { using System; using System.Collections; using System.IO; using System.Text; using NVelocity.Context; using NVelocity.Runtime.Parser; using NVelocity.Runtime.Parser.Node; /// <summary> /// Macro.java /// /// Macro implements the macro definition directive of VTL. /// /// example : /// /// #macro( isnull $i ) /// #if( $i ) /// $i /// #end /// #end /// /// This object is used at parse time to mainly process and register the /// macro. It is used inline in the parser when processing a directive. /// /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a></author> /// <version> $Id: Macro.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $</version> public class Macro : Directive { public override String Name { get { return "macro"; } set { throw new NotSupportedException(); } } public override int Type { get { return DirectiveConstants_Fields.BLOCK; } } private static bool debugMode = false; /// <summary> Return name of this directive. /// </summary> /// <summary> Return type of this directive. /// </summary> /// <summary> render() doesn't do anything in the final output rendering. /// There is no output from a #macro() directive. /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, Node node) { /* * do nothing : We never render. The VelocimacroProxy object does that */ return true; } public override void init(RuntimeServices rs, InternalContextAdapter context, Node node) { base.init(rs, context, node); /* * again, don't do squat. We want the AST of the macro * block to hang off of this but we don't want to * init it... it's useless... */ return; } /// <summary> /// Used by Parser.java to process VMs withing the parsing process /// /// processAndRegister() doesn't actually render the macro to the output /// Processes the macro body into the internal representation used by the /// VelocimacroProxy objects, and if not currently used, adds it /// to the macro Factory /// </summary> public static void processAndRegister(RuntimeServices rs, Node node, String sourceTemplate) { /* * There must be at least one arg to #macro, * the name of the VM. Note that 0 following * args is ok for naming blocks of HTML */ int numArgs = node.jjtGetNumChildren(); /* * this number is the # of args + 1. The + 1 * is for the block tree */ if (numArgs < 2) { /* * error - they didn't name the macro or * define a block */ rs.error("#macro error : Velocimacro must have name as 1st " + "argument to #macro()"); return; } /* * get the arguments to the use of the VM */ String[] argArray = getArgArray(node); /* * now, try and eat the code block. Pass the root. */ IList macroArray = getASTAsStringArray(node.jjtGetChild(numArgs - 1)); /* * make a big string out of our macro */ StringBuilder temp = new StringBuilder(); for (int i = 0; i < macroArray.Count; i++) temp.Append(macroArray[i]); String macroBody = temp.ToString(); /* * now, try to add it. The Factory controls permissions, * so just give it a whack... */ bool bRet = rs.addVelocimacro(argArray[0], macroBody, argArray, sourceTemplate); return; } /// <summary> creates an array containing the literal /// strings in the macro arguement /// </summary> private static String[] getArgArray(Node node) { /* * remember : this includes the block tree */ int numArgs = node.jjtGetNumChildren(); numArgs--; // avoid the block tree... String[] argArray = new String[numArgs]; int i = 0; /* * eat the args */ while (i < numArgs) { argArray[i] = node.jjtGetChild(i).FirstToken.image; /* * trim off the leading $ for the args after the macro name. * saves everyone else from having to do it */ if (i > 0) { if (argArray[i].StartsWith("$")) argArray[i] = argArray[i].Substring(1, (argArray[i].Length) - (1)); } i++; } if (debugMode) { Console.Out.WriteLine("Macro.getArgArray() : #args = " + numArgs); Console.Out.Write(argArray[0] + "("); for (i = 1; i < numArgs; i++) Console.Out.Write(" " + argArray[i]); Console.Out.WriteLine(" )"); } return argArray; } /// <summary> Returns an array of the literal rep of the AST /// </summary> private static IList getASTAsStringArray(Node rootNode) { /* * this assumes that we are passed in the root * node of the code block */ Token t = rootNode.FirstToken; Token tLast = rootNode.LastToken; /* * now, run down the part of the tree bounded by * our first and last tokens */ ArrayList list = new ArrayList(); t = rootNode.FirstToken; while (t != tLast) { list.Add(NodeUtils.tokenLiteral(t)); t = t.next; } /* * make sure we get the last one... */ list.Add(NodeUtils.tokenLiteral(t)); return list; } } } --- NEW FILE: VMProxyArg.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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/>. */ using System; using System.IO; using NVelocity.Context; using NVelocity.Exception; using NVelocity.Runtime.Parser; using NVelocity.Runtime.Parser.Node; using NVelocity.Util; /// <summary> The function of this class is to proxy for the calling parameter to the VM. /// * /// This class is designed to be used in conjunction with the VMContext class /// which knows how to get and set values via it, rather than a simple get() /// or put() from a hashtable-like object. /// * /// There is probably a lot of undocumented subtlty here, so step lightly. /// * /// We rely on the observation that an instance of this object has a constant /// state throughout its lifetime as it's bound to the use-instance of a VM. /// In other words, it's created by the VelocimacroProxy class, to represent /// one of the arguments to a VM in a specific template. Since the template /// is fixed (it's a file...), we don't have to worry that the args to the VM /// will change. Yes, the VM will be called in other templates, or in other /// places on the same template, bit those are different use-instances. /// * /// These arguments can be, in the lingo of /// the parser, one of : /// <ul> /// <li> Reference() : anything that starts with '$' /// <li> StringLiteral() : something like "$foo" or "hello geir" /// <li> NumberLiteral() : 1, 2 etc /// <li> IntegerRange() : [ 1..2] or [$foo .. $bar] /// <li> ObjectArray() : [ "a", "b", "c"] /// <li> True() : true /// <li> False() : false /// <li>Word() : not likely - this is simply allowed by the parser so we can have /// syntactical sugar like #foreach($a in $b) where 'in' is the Word /// </ul> /// Now, Reference(), StringLit, NumberLit, IntRange, ObjArr are all dynamic things, so /// their value is gotten with the use of a context. The others are constants. The trick /// we rely on is that the context rather than this class really represents the /// state of the argument. We are simply proxying for the thing, returning the proper value /// when asked, and storing the proper value in the appropriate context when asked. /// * /// So, the hope here, so an instance of this can be shared across threads, is to /// keep any dynamic stuff out of it, relying on trick of having the appropriate /// context handed to us, and when a constant argument, letting VMContext punch that /// into a local context. /// /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a> /// </author> /// <version> $Id: VMProxyArg.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ /// /// </version> public class VMProxyArg { public virtual String CallerReference { get { return callerReference; } } public virtual String ContextReference { get { return contextReference; } } public virtual SimpleNode NodeTree { get { return nodeTree; } } public virtual Object StaticObject { get { return staticObject; } } public virtual int Type { get { return type; } } /// <summary>type of arg I will have /// </summary> private int type = 0; /// <summary>the AST if the type is such that it's dynamic (ex. JJTREFERENCE ) /// </summary> private SimpleNode nodeTree = null; /// <summary>reference for the object if we proxy for a static arg like an NumberLiteral /// </summary> private Object staticObject = null; /// <summary>not used in this impl : carries the appropriate user context /// </summary> private InternalContextAdapter usercontext = null; /// <summary>number of children in our tree if a reference /// </summary> private int numTreeChildren = 0; /// <summary>our identity in the current context /// </summary> private String contextReference = null; /// <summary>the reference we are proxying for /// </summary> private String callerReference = null; /// <summary>the 'de-dollared' reference if we are a ref but don't have a method attached /// </summary> private String singleLevelRef = null; /// <summary>by default, we are dynamic. safest /// </summary> private bool constant = false; /// <summary>in the event our type is switched - we don't care really what it is /// </summary> private const int GENERALSTATIC = - 1; private RuntimeServices rsvc = null; /// <summary> ctor for current impl /// * /// takes the reference literal we are proxying for, the literal /// the VM we are for is called with... /// * /// </summary> /// <param name="contextRef">reference arg in the definition of the VM, used in the VM /// </param> /// <param name="callerRef"> reference used by the caller as an arg to the VM /// </param> /// <param name="t"> type of arg : JJTREFERENCE, JJTTRUE, etc /// /// </param> public VMProxyArg(RuntimeServices rs, String contextRef, String callerRef, int t) { rsvc = rs; contextReference = contextRef; callerReference = callerRef; type = t; /* * make our AST if necessary */ setup(); /* * if we are multi-node tree, then save the size to * avoid fn call overhead */ if (nodeTree != null) numTreeChildren = nodeTree.jjtGetNumChildren(); /* * if we are a reference, and 'scalar' (i.e. $foo ) * then get the de-dollared ref so we can * hit our context directly, avoiding the AST */ if (type == ParserTreeConstants.JJTREFERENCE) { if (numTreeChildren == 0) { /* * do this properly and use the Reference node */ singleLevelRef = ((ASTReference) nodeTree).RootString; } } } /// <summary> tells if arg we are poxying for is /// dynamic or constant. /// * /// </summary> /// <returns>true of constant, false otherwise /// /// </returns> public virtual bool isConstant() { return constant; } /// <summary> Invoked by VMContext when Context.put() is called for a proxied reference. /// * /// </summary> /// <param name="context">context to modify via direct placement, or AST.setValue() /// </param> /// <param name="o"> new value of reference /// </param> /// <returns>Object currently null /// /// </returns> public virtual Object setObject(InternalContextAdapter context, Object o) { /* * if we are a reference, we could be updating a property */ if (type == ParserTreeConstants.JJTREFERENCE) { if (numTreeChildren > 0) { /* * we are a property, and being updated such as * #foo( $bar.BangStart) */ try { ((ASTReference) nodeTree).setValue(context, o); } catch (MethodInvocationException mie) { rsvc.error("VMProxyArg.getObject() : method invocation error setting value : " + mie); } } else { /* * we are a 'single level' reference like $foo, so we can set * out context directly */ context.Put(singleLevelRef, o); // alternate impl : usercontext.put( singleLevelRef, o); } } else { /* * if we aren't a reference, then we simply switch type, * get a new value, and it doesn't go into the context * * in current impl, this shouldn't happen. */ type = GENERALSTATIC; staticObject = o; rsvc.error("VMProxyArg.setObject() : Programmer error : I am a constant! No setting! : " + contextReference + " / " + callerReference); } return null; } /// <summary> returns the value of the reference. Generally, this is only /// called for dynamic proxies, as the static ones should have /// been stored in the VMContext's localcontext store /// * /// </summary> /// <param name="context">Context to use for getting current value /// </param> /// <returns>Object value /// * /// /// </returns> public virtual Object getObject(InternalContextAdapter context) { try { /* * we need to output based on our type */ Object retObject = null; if (type == ParserTreeConstants.JJTREFERENCE) { /* * two cases : scalar reference ($foo) or multi-level ($foo.bar....) */ if (numTreeChildren == 0) { /* * if I am a single-level reference, can I not get get it out of my context? */ retObject = context.Get(singleLevelRef); } else { /* * I need to let the AST produce it for me. */ retObject = nodeTree.execute(null, context); } } else if (type == ParserTreeConstants.JJTOBJECTARRAY) { retObject = nodeTree.value_Renamed(context); } else if (type == ParserTreeConstants.JJTINTEGERRANGE) { retObject = nodeTree.value_Renamed(context); } else if (type == ParserTreeConstants.JJTTRUE) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTFALSE) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTSTRINGLITERAL) { retObject = nodeTree.value_Renamed(context); } else if (type == ParserTreeConstants.JJTNUMBERLITERAL) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTTEXT) { /* * this really shouldn't happen. text is just a thowaway arg for #foreach() */ try { StringWriter writer = new StringWriter(); nodeTree.render(context, writer); retObject = writer; } catch (Exception e) { rsvc.error("VMProxyArg.getObject() : error rendering reference : " + e); } } else if (type == GENERALSTATIC) { retObject = staticObject; } else { rsvc.error("Unsupported VM arg type : VM arg = " + callerReference + " type = " + type + "( VMProxyArg.getObject() )"); } return retObject; } catch (MethodInvocationException mie) { /* * not ideal, but otherwise we propogate out to the * VMContext, and the Context interface's put/get * don't throw. So this is a the best compromise * I can think of */ rsvc.error("VMProxyArg.getObject() : method invocation error getting value : " + mie); return null; } } /// <summary> does the housekeeping upon creationg. If a dynamic type /// it needs to make an AST for further get()/set() operations /// Anything else is constant. /// </summary> private void setup() { switch (type) { case ParserTreeConstants.JJTINTEGERRANGE: case ParserTreeConstants.JJTREFERENCE: case ParserTreeConstants.JJTOBJECTARRAY: case ParserTreeConstants.JJTSTRINGLITERAL: case ParserTreeConstants.JJTTEXT: { /* * dynamic types, just render */ constant = false; try { /* * fakie : wrap in directive to get the parser to treat our args as args * it doesn't matter that #include() can't take all these types, because we * just want the parser to consider our arg as a Directive/VM arg rather than * as if inline in schmoo */ String buff = "#include(" + callerReference + " ) "; //ByteArrayInputStream inStream = new ByteArrayInputStream( buff.getBytes() ); //UPGRADE_ISSUE: The equivalent of constructor 'java.io.BufferedReader.BufferedReader' is incompatible with the expected type in C#. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1109"' TextReader br = new StringReader(buff); nodeTree = rsvc.parse(br, "VMProxyArg:" + callerReference, true); /* * now, our tree really is the first DirectiveArg(), and only one */ nodeTree = (SimpleNode) nodeTree.jjtGetChild(0).jjtGetChild(0); /* * sanity check */ if (nodeTree != null && nodeTree.Type != type) { rsvc.error("VMProxyArg.setup() : programmer error : type doesn't match node type."); } /* * init. We can do this as they are only references */ nodeTree.init(null, rsvc); } catch (Exception e) { rsvc.error("VMProxyArg.setup() : exception " + callerReference + " : " + StringUtils.stackTrace(e)); } break; } case ParserTreeConstants.JJTTRUE: { constant = true; staticObject = true; break; } case ParserTreeConstants.JJTFALSE: { constant = true; staticObject = false; break; } case ParserTreeConstants.JJTNUMBERLITERAL: { constant = true; staticObject = Int32.Parse(callerReference); break; } case ParserTreeConstants.JJTWORD: { /* * this is technically an error... */ rsvc.error("Unsupported arg type : " + callerReference + " You most likely intended to call a VM with a string literal, so enclose with ' or \" characters. (VMProxyArg.setup())"); constant = true; staticObject = new String(callerReference.ToCharArray()); break; } default: { rsvc.error(" VMProxyArg.setup() : unsupported type : " + callerReference); } break; } } /* * CODE FOR ALTERNATE IMPL : please ignore. I will remove when confortable with current. */ /// <summary> not used in current impl /// * /// Constructor for alternate impl where VelProxy class would make new /// VMProxyArg objects, and use this contructor to avoid reparsing the /// reference args /// * /// that impl also had the VMProxyArg carry it's context /// </summary> public VMProxyArg(VMProxyArg model, InternalContextAdapter c) { usercontext = c; contextReference = model.ContextReference; callerReference = model.CallerReference; nodeTree = model.NodeTree; staticObject = model.StaticObject; type = model.Type; if (nodeTree != null) numTreeChildren = nodeTree.jjtGetNumChildren(); if (type == ParserTreeConstants.JJTREFERENCE) { if (numTreeChildren == 0) { /* * use the reference node to do this... */ singleLevelRef = ((ASTReference) nodeTree).RootString; } } } } } --- NEW FILE: ParseDirectiveException.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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/>. */ using System; using System.Collections; /// <summary> Exception for #parse() problems /// * /// </summary> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a> /// </author> /// <version> $Id: ParseDirectiveException.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $ /// /// </version> public class ParseDirectiveException : Exception { private void InitBlock() { filenameStack = new Stack(); } public override String Message { get { String returnStr = "#parse() exception : depth = " + depthCount + " -> " + msg; returnStr += " File stack : "; try { while (!(filenameStack.Count == 0)) { returnStr += (String) filenameStack.Pop(); returnStr += " -> "; } } catch (Exception e) { } return returnStr; } } //UPGRADE_NOTE: The initialization of 'filenameStack' was moved to method 'InitBlock'. 'ms-help://MS.VSCC/commoner/redir/redirect.htm?keyword="jlca1005"' private Stack filenameStack; private String msg = ""; private int depthCount = 0; /// <summary> Constructor /// </summary> internal ParseDirectiveException(String m, int i) { InitBlock(); msg = m; depthCount = i; } /// <summary> Get a message. /// </summary> /// <summary> Add a file to the filename stack /// </summary> public virtual void addFile(String s) { Object temp_object; temp_object = s; Object generatedAux = temp_object; filenameStack.Push(temp_object); } } } --- NEW FILE: Foreach.cs --- //using ArrayIterator = NVelocity.Util.ArrayIterator; //using EnumerationIterator = NVelocity.Util.EnumerationIterator; namespace NVelocity.Runtime.Directive { using System; using System.Collections; using System.IO; using NVelocity.Context; using NVelocity.Runtime.Parser.Node; using NVelocity.Util.Introspection; /// <summary> /// Foreach directive used for moving through arrays, /// or objects that provide an Iterator. /// </summary> /// <author> <a href="mailto:jv...@ap...">Jason van Zyl</a></author> /// <author> <a href="mailto:ge...@op...">Geir Magnusson Jr.</a></author> /// <version> $Id: Foreach.cs,v 1.5 2005/11/16 07:01:50 intesar66 Exp $</version> public class Foreach : Directive { public override String Name { get { return "foreach"; } set { throw new NotSupportedException(); } } public override int Type { get { return DirectiveConstants_Fields.BLOCK; } } /// <summary> Return name of this directive. /// </summary> /// <summary> Return type of this directive. /// </summary> private static int UNKNOWN = - 1; /// <summary> Flag to indicate that the list object being used /// in an array. /// </summary> private const int INFO_ARRAY = 1; /// <summary> Flag to indicate that the list object being used /// provides an Iterator. /// </summary> private const int INFO_ITERATOR = 2; /// <summary> Flag to indicate that the list object being used /// is a Map. /// </summary> private const int INFO_MAP = 3; /// <summary> Flag to indicate that the list object being used /// is a Collection. /// </summary> private const int INFO_COLLECTION = 4; /// <summary> Flag to indicate that the list object being used /// is an Enumeration /// </summary> private const int INFO_ENUMERATION = 5; /// <summary> Flag to indicate that the list object being used /// is an IEnumerable /// </summary> private const int INFO_ENUMERABLE = 6; /// <summary> The name of the variable to use when placing /// the counter value into the context. Right /// now the default is $velocityCount. /// </summary> private String counterName; /// <summary> What value to start the loop counter at. /// </summary> private int counterInitialValue; /// <summary> The reference name used to access each /// of the elements in the list object. It /// is the $item in the following: /// /// #foreach ($item in $list) /// /// This can be used class wide because /// it is immutable. /// </summary> private String elementKey; /// <summary> simple init - init the tree and get the elementKey from /// the AST /// </summary> public override void init(RuntimeServices rs, InternalContextAdapter context, INode node) { base.init(rs, context, node); counterName = rsvc.getString(RuntimeConstants_Fields.COUNTER_NAME); counterInitialValue = rsvc.getInt(RuntimeConstants_Fields.COUNTER_INITIAL_VALUE); /* * this is really the only thing we can do here as everything * else is context sensitive */ elementKey = node.jjtGetChild(0).FirstToken.image.Substring(1); } /// <summary> returns an Iterator to the collection in the #foreach() /// /// </summary> /// <param name="context"> current context /// </param> /// <param name="node"> AST node /// </param> /// <returns>Iterator to do the dataset /// /// </returns> private IEnumerator getIterator(InternalContextAdapter context, INode node) { /* * get our list object, and punt if it's null. */ Object listObject = node.jjtGetChild(2).value_Renamed(context); if (listObject == null) return null; /* * See if we already know what type this is. * Use the introspection cache */ int type = UNKNOWN; IntrospectionCacheData icd = context.ICacheGet(this); Type c = listObject.GetType(); /* * if we have an entry in the cache, and the Class we have * cached is the same as the Class of the data object * then we are ok */ if (icd != null && icd.contextData == c) { /* dig the type out of the cata object */ type = ((Int32) icd.thingy); } /* * If we still don't know what this is, * figure out what type of object the list * element is, and get the iterator for it */ if (type == UNKNOWN) { if (listObject.GetType().IsArray) type = INFO_ARRAY; // NOTE: IDictionary needs to come before ICollection as it support ICollection else if (listObject is IDictionary) type = INFO_MAP; else if (listObject is ICollection) type = INFO_COLLECTION; else if (listObject is IEnumerable) type = INFO_ENUMERABLE; else if (listObject is IEnumerator) type = INFO_ENUMERATION; /* * if we did figure it out, cache it */ if (type != UNKNOWN) { icd = new IntrospectionCacheData(); icd.thingy = type; icd.contextData = c; context.ICachePut(this, icd); } } /* * now based on the type from either cache or examination... */ switch (type) { case INFO_COLLECTION: return ((ICollection) listObject).GetEnumerator(); case INFO_ENUMERABLE: return ((IEnumerable) listObject).GetEnumerator(); case INFO_ENUMERATION: rsvc.warn("Warning! The reference " + node.jjtGetChild(2).FirstToken.image + " is an Enumeration in the #foreach() loop at [" + Line + "," + Column + "]" + " in template " + context.CurrentTemplateName + ". Because it's not resetable," + " if used in more than once, this may lead to" + " unexpected results."); return (IEnumerator) listObject; case INFO_ARRAY: return ((Array) listObject).GetEnumerator(); case INFO_MAP: return ((IDictionary) listObject).GetEnumerator(); default: /* we have no clue what this is */ rsvc.warn("Could not determine type of enumerator (" + listObject.GetType().Name + ") in " + "#foreach loop for " + node.jjtGetChild(2).FirstToken.image + " at [" + Line + "," + Column + "]" + " in template " + context.CurrentTemplateName); return null; } } /// <summary> renders the #foreach() block /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, INode node) { /* * do our introspection to see what our collection is */ IEnumerator i = getIterator(context, node); if (i == null) return false; int counter = counterInitialValue; /* * save the element key if there is one, * and the loop counter */ Object o = context.Get(elementKey); Object ctr = context.Get(counterName); while (i.MoveNext()) { context.Put(counterName, counter); context.Put(elementKey, i.Current); node.jjtGetChild(3).render(context, writer); counter++; } /* * restores the loop counter (if we were nested) * if we have one, else just removes */ if (ctr != null) { context.Put(counterName, ctr); } else { context.Remove(counterName); } /* * restores element key if exists * otherwise just removes */ if (o != null) { context.Put(elementKey, o); } else { context.Remove(elementKey); } return true; } } } --- NEW FILE: DirectiveConstants.cs --- namespace NVelocity.Runtime.Directive { /* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 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", "Velocity", 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 ap...@ap.... * * 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 ... [truncated message content] |