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