001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.jasper.compiler;
017:
018: import java.util.Stack;
019: import java.net.URL;
020: import java.net.MalformedURLException;
021: import org.apache.jasper.JspCompilationContext;
022:
023: /**
024: * Mark represents a point in the JSP input.
025: *
026: * @author Anil K. Vijendran
027: */
028: final class Mark {
029:
030: // position within current stream
031: int cursor, line, col;
032:
033: // directory of file for current stream
034: String baseDir;
035:
036: // current stream
037: char[] stream = null;
038:
039: // fileid of current stream
040: private int fileId;
041:
042: // name of the current file
043: private String fileName;
044:
045: /*
046: * stack of stream and stream state of streams that have included
047: * current stream
048: */
049: private Stack includeStack = null;
050:
051: // encoding of current file
052: private String encoding = null;
053:
054: // reader that owns this mark (so we can look up fileid's)
055: private JspReader reader;
056:
057: private JspCompilationContext ctxt;
058:
059: /**
060: * Constructor
061: *
062: * @param reader JspReader this mark belongs to
063: * @param inStream current stream for this mark
064: * @param fileId id of requested jsp file
065: * @param name JSP file name
066: * @param inBaseDir base directory of requested jsp file
067: * @param inEncoding encoding of current file
068: */
069: Mark(JspReader reader, char[] inStream, int fileId, String name,
070: String inBaseDir, String inEncoding) {
071:
072: this .reader = reader;
073: this .ctxt = reader.getJspCompilationContext();
074: this .stream = inStream;
075: this .cursor = 0;
076: this .line = 1;
077: this .col = 1;
078: this .fileId = fileId;
079: this .fileName = name;
080: this .baseDir = inBaseDir;
081: this .encoding = inEncoding;
082: this .includeStack = new Stack();
083: }
084:
085: /**
086: * Constructor
087: */
088: Mark(Mark other) {
089:
090: this .reader = other.reader;
091: this .ctxt = other.reader.getJspCompilationContext();
092: this .stream = other.stream;
093: this .fileId = other.fileId;
094: this .fileName = other.fileName;
095: this .cursor = other.cursor;
096: this .line = other.line;
097: this .col = other.col;
098: this .baseDir = other.baseDir;
099: this .encoding = other.encoding;
100:
101: // clone includeStack without cloning contents
102: includeStack = new Stack();
103: for (int i = 0; i < other.includeStack.size(); i++) {
104: includeStack.addElement(other.includeStack.elementAt(i));
105: }
106: }
107:
108: /**
109: * Constructor
110: */
111: Mark(JspCompilationContext ctxt, String filename, int line, int col) {
112:
113: this .reader = null;
114: this .ctxt = ctxt;
115: this .stream = null;
116: this .cursor = 0;
117: this .line = line;
118: this .col = col;
119: this .fileId = -1;
120: this .fileName = filename;
121: this .baseDir = "le-basedir";
122: this .encoding = "le-endocing";
123: this .includeStack = null;
124: }
125:
126: /**
127: * Sets this mark's state to a new stream.
128: * It will store the current stream in it's includeStack.
129: *
130: * @param inStream new stream for mark
131: * @param inFileId id of new file from which stream comes from
132: * @param inBaseDir directory of file
133: * @param inEncoding encoding of new file
134: */
135: public void pushStream(char[] inStream, int inFileId, String name,
136: String inBaseDir, String inEncoding) {
137: // store current state in stack
138: includeStack.push(new IncludeState(cursor, line, col, fileId,
139: fileName, baseDir, encoding, stream));
140:
141: // set new variables
142: cursor = 0;
143: line = 1;
144: col = 1;
145: fileId = inFileId;
146: fileName = name;
147: baseDir = inBaseDir;
148: encoding = inEncoding;
149: stream = inStream;
150: }
151:
152: /**
153: * Restores this mark's state to a previously stored stream.
154: * @return The previous Mark instance when the stream was pushed, or null
155: * if there is no previous stream
156: */
157: public Mark popStream() {
158: // make sure we have something to pop
159: if (includeStack.size() <= 0) {
160: return null;
161: }
162:
163: // get previous state in stack
164: IncludeState state = (IncludeState) includeStack.pop();
165:
166: // set new variables
167: cursor = state.cursor;
168: line = state.line;
169: col = state.col;
170: fileId = state.fileId;
171: fileName = state.fileName;
172: baseDir = state.baseDir;
173: stream = state.stream;
174: return this ;
175: }
176:
177: // -------------------- Locator interface --------------------
178:
179: public int getLineNumber() {
180: return line;
181: }
182:
183: public int getColumnNumber() {
184: return col;
185: }
186:
187: public String getSystemId() {
188: return getFile();
189: }
190:
191: public String getPublicId() {
192: return null;
193: }
194:
195: public String toString() {
196: return getFile() + "(" + line + "," + col + ")";
197: }
198:
199: public String getFile() {
200: return this .fileName;
201: }
202:
203: /**
204: * Gets the URL of the resource with which this Mark is associated
205: *
206: * @return URL of the resource with which this Mark is associated
207: *
208: * @exception MalformedURLException if the resource pathname is incorrect
209: */
210: public URL getURL() throws MalformedURLException {
211: return ctxt.getResource(getFile());
212: }
213:
214: public String toShortString() {
215: return "(" + line + "," + col + ")";
216: }
217:
218: public boolean equals(Object other) {
219: if (other instanceof Mark) {
220: Mark m = (Mark) other;
221: return this .reader == m.reader && this .fileId == m.fileId
222: && this .cursor == m.cursor && this .line == m.line
223: && this .col == m.col;
224: }
225: return false;
226: }
227:
228: /**
229: * @return true if this Mark is greather than the <code>other</code>
230: * Mark, false otherwise.
231: */
232: public boolean isGreater(Mark other) {
233:
234: boolean greater = false;
235:
236: if (this .line > other.line) {
237: greater = true;
238: } else if (this .line == other.line && this .col > other.col) {
239: greater = true;
240: }
241:
242: return greater;
243: }
244:
245: /**
246: * Keep track of parser before parsing an included file.
247: * This class keeps track of the parser before we switch to parsing an
248: * included file. In other words, it's the parser's continuation to be
249: * reinstalled after the included file parsing is done.
250: */
251: class IncludeState {
252: int cursor, line, col;
253: int fileId;
254: String fileName;
255: String baseDir;
256: String encoding;
257: char[] stream = null;
258:
259: IncludeState(int inCursor, int inLine, int inCol, int inFileId,
260: String name, String inBaseDir, String inEncoding,
261: char[] inStream) {
262: cursor = inCursor;
263: line = inLine;
264: col = inCol;
265: fileId = inFileId;
266: fileName = name;
267: baseDir = inBaseDir;
268: encoding = inEncoding;
269: stream = inStream;
270: }
271: }
272:
273: }
|