/* * 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 acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xalan" 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 apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * 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 and was * originally based on software copyright (c) 1999, Lotus * Development Corporation., http://www.lotus.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.xpath; import org.apache.xpath.XPathContext; import org.apache.xpath.objects.XObject; import javax.xml.transform.TransformerException; /** * <meta name="usage" content="internal"/> * Defines a class to keep track of a stack for * template arguments and variables. * * <p>This has been changed from the previous incarnations of this * class to be fairly low level.</p> */ public final class VariableStack implements Cloneable { /** * Constructor for a variable stack. */ public VariableStack() { reset(); } /** * Returns a clone of this variable stack. * * @return a clone of this variable stack. * * @throws CloneNotSupportedException */ public synchronized Object clone() throws CloneNotSupportedException { VariableStack vs = (VariableStack) super.clone(); // I *think* I can get away with a shallow clone here? vs._sf = (XObject[]) _sf.clone(); vs._links = (int[]) _links.clone(); return vs; } /** * The stack frame where all variables and params will be kept. * @serial */ XObject[] _sf = new XObject[XPathContext.RECURSIONLIMIT * 2]; /** * The top of the stack frame (<code>_sf</code>). * @serial */ int _top; /** * The bottom index of the current frame (relative to <code>_sf</code>). * @serial */ private int _cfb; /** * The stack of frame positions. I call 'em links because of distant * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html"> * Motorola 68000 assembler</a> memories. :-) * @serial */ int[] _links = new int[XPathContext.RECURSIONLIMIT]; /** * The top of the links stack. */ int _linksTop; /** * Get the element at the given index, regardless of stackframe. * * @param i index from zero. * * @return The item at the given index. */ public final XObject elementAt(final int i) { return _sf[i]; } /** * Get size of the stack. * * @return the total size of the execution stack. */ public final int size() { return _top; } /** * Reset the stack to a start position. * * @return the total size of the execution stack. */ public final void reset() { _top = 0; _linksTop = 0; // Adding one here to the stack of frame positions will allow us always // to look one under without having to check if we're at zero. // (As long as the caller doesn't screw up link/unlink.) _links[_linksTop++] = 0; } /** * Set the current stack frame. * * @param sf The new stack frame position. */ public final void setStackFrame(int sf) { _cfb = sf; } /** * Get the position from where the search should start, * which is either the searchStart property, or the top * of the stack if that value is -1. * * @return The current stack frame position. */ public final int getStackFrame() { return _cfb; } /** * Allocates memory (called a stackframe) on the stack; used to store * local variables and parameter arguments. * * <p>I use the link/unlink concept because of distant * <a href="http://math.millikin.edu/mprogers/Courses/currentCourses/CS481-ComputerArchitecture/cs481.Motorola68000.html"> * Motorola 68000 assembler</a> memories.</p> * * @param size The size of the stack frame allocation. This ammount should * normally be the maximum number of variables that you can have allocated * at one time in the new stack frame. * * @return The bottom of the stack frame, from where local variable addressing * should start from. */ public final int link(final int size) { _cfb = _top; _top += size; if (_top >= _sf.length) { XObject newsf[] = new XObject[_sf.length + (1024 * 4) + size]; System.arraycopy(_sf, 0, newsf, 0, _sf.length); _sf = newsf; } if (_linksTop+1 >= _links.length) { int newlinks[] = new int[_links.length + (1024 * 2)]; System.arraycopy(_links, 0, newlinks, 0, _links.length); _links = newlinks; } _links[_linksTop++] = _cfb; return _cfb; } /** * Free up the stack frame that was last allocated with * {@link link(int size)}. */ public final void unlink() { _top = _links[--_linksTop]; _cfb = _links[_linksTop - 1]; } /** * Set a local variable or parameter in the current stack frame. * * * @param index Local variable index relative to the current stack * frame bottom. * * @param val The value of the variable that is being set. */ public final void setLocalVariable(int index, XObject val) { _sf[index+_cfb] = val; } /** * Set a local variable or parameter in the specified stack frame. * * * @param index Local variable index relative to the current stack * frame bottom. * * @param val The value of the variable that is being set. */ public final void setLocalVariable(int index, XObject val, int stackFrame) { _sf[index+stackFrame] = val; } /** * Get a local variable or parameter in the current stack frame. * * * @param xctxt The XPath context, which must be passed in order to * lazy evaluate variables. * * @param index Local variable index relative to the current stack * frame bottom. * * @return The value of the variable. * * @throws TransformerException */ public final XObject getLocalVariable(XPathContext xctxt, int index) throws TransformerException { index += _cfb; XObject val = _sf[index]; // Lazy execution of variables. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE) return (_sf[index] = val.execute(xctxt)); return val; } /** * Get a local variable or parameter in the current stack frame. * * * @param index Local variable index relative to the given * frame bottom. * * @return The value of the variable. * * @throws TransformerException */ public final XObject getLocalVariable(int index, int frame) throws TransformerException { index += frame; XObject val = _sf[index]; return val; } /** * Tell if a local variable has been set or not. * * @param index Local variable index relative to the current stack * frame bottom. * * @return true if the value at the index is not null. * * @throws TransformerException */ public final boolean isLocalSet(int index) throws TransformerException { return (_sf[index + _cfb] != null); } private static XObject[] m_nulls = new XObject[1024]; /** * Use this to clear the variables in a section of the stack. This is * used to clear the parameter section of the stack, so that default param * values can tell if they've already been set. It is important to note that * this function has a 1K limitation. * * @param start The start position, relative to the current local stack frame. * @param len The number of slots to be cleared. */ public final void clearLocalSlots(int start, int len) { start+=_cfb; System.arraycopy(m_nulls, 0, _sf, start, len); } /** * Set a global variable or parameter in the global stack frame. * * * @param index Local variable index relative to the global stack frame * bottom. * * @param val The value of the variable that is being set. */ public final void setGlobalVariable(final int index, final XObject val) { _sf[index] = val; } /** * Get a global variable or parameter from the global stack frame. * * * @param xctxt The XPath context, which must be passed in order to * lazy evaluate variables. * * @param index Global variable index relative to the global stack * frame bottom. * * @return The value of the variable. * * @throws TransformerException */ public final XObject getGlobalVariable(XPathContext xctxt, final int index) throws TransformerException { XObject val = _sf[index]; // Lazy execution of variables. if (val.getType() == XObject.CLASS_UNRESOLVEDVARIABLE) return (_sf[index] = val.execute(xctxt)); return val; } } // end VariableStack