2 * Copyright (c) 2003-2004 Christopher Lenz and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * Christopher Lenz - initial API and implementation
11 * $Id: CssCodeReader.java,v 1.1 2004-09-02 18:07:13 jsurfer Exp $
14 package net.sourceforge.phpeclipse.css.core.internal.text;
16 import java.io.IOException;
17 import java.io.Reader;
19 import org.eclipse.jface.text.BadLocationException;
20 import org.eclipse.jface.text.IDocument;
25 public class CssCodeReader extends Reader {
27 // Constants ---------------------------------------------------------------
30 * Constant for configuring a reader to read the document backwards.
32 public static final int BACKWARD = -1;
35 * Constant for configuring a reader to read the document forwards.
37 public static final int FORWARD = 1;
39 // Instance Variables ------------------------------------------------------
42 * The document to read. Is <code>null</code> when the reader is closed.
44 private IDocument document;
47 * The direction in which the document should be read. Can be either
48 * {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD}.
50 private int direction;
53 * The offset at which to start reading.
58 * The offset at which to end reading.
63 * Whether comments should be skipped.
65 private boolean skipComments;
68 * Whether string literals should be skipped.
70 private boolean skipStrings;
73 * Whether whitespace characters should be skipped.
75 private boolean skipWhitespace;
77 // Constructors ------------------------------------------------------------
82 * @param document the document to read
83 * @param offset the offset at which to start reading
85 public CssCodeReader(IDocument document, int offset) {
86 this(document, offset, document.getLength() - offset, FORWARD);
92 * @param document the document to read
93 * @param offset the offset at which to start reading
94 * @param length the number of characters to read at most
96 public CssCodeReader(IDocument document, int offset, int length) {
97 this(document, offset, length, FORWARD);
103 * @param document the document to read
104 * @param offset the offset at which to start reading
105 * @param length the number of characters to read at most
106 * @param direction the reading direction (either
107 * {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD})
109 public CssCodeReader(IDocument document, int offset, int length,
111 this(document, offset, length, direction, true, false, false);
117 * @param document the document to read
118 * @param offset the offset at which to start reading
119 * @param length the number of characters to read at most
120 * @param direction the reading direction (either
121 * {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD})
122 * @param skipComments whether the reader should skip comments
123 * @param skipStrings whether the reader should skip strings
124 * @param skipWhitespace whether the reader should skip whitespace
126 public CssCodeReader(IDocument document, int offset, int length,
127 int direction, boolean skipComments, boolean skipStrings,
128 boolean skipWhitespace) {
129 if ((direction != BACKWARD) && (direction != FORWARD)) {
130 throw new IllegalArgumentException();
132 if ((offset < 0) || (offset > document.getLength())) {
133 throw new IllegalArgumentException();
135 this.document = document;
136 this.offset = offset;
137 this.direction = direction;
138 if (direction == FORWARD) {
139 end = Math.min(document.getLength(), offset + length);
141 end = Math.max(0, offset - length);
143 this.skipComments = skipComments;
144 this.skipStrings = skipStrings;
145 this.skipWhitespace = skipWhitespace;
148 // Reader Implementation ---------------------------------------------------
151 * @see Reader#close()
153 public void close() {
158 * @see Reader#read(char[], int, int)
160 public int read(char[] cbuf, int off, int len) throws IOException {
161 for (int i = off; i < off + len; i++) {
178 public int read() throws IOException {
179 if (document == null) {
180 throw new IllegalStateException();
183 if (direction == FORWARD) {
184 return readForwards();
186 return readBackwards();
188 } catch (BadLocationException ble) {
189 throw new IOException(ble.getMessage());
193 // Public Methods ----------------------------------------------------------
196 * Returns the document that is being read.
198 * @return The document
200 public IDocument getDocument() {
205 * Returns the offset of the last read character. Should only be called
206 * after read has been called.
208 * @return The offset of the last read character
210 public int getOffset() {
211 return (direction == FORWARD) ? offset - 1 : offset;
215 * Returns whether the reader is currently configured to skip comments.
217 * @return <code>true</code> if the reader is skipping comments and
218 * <code>false</code> otherwise
220 public boolean isSkippingComments() {
225 * Configures the reader to skip comment blocks.
227 * @param skipComments Whether comments should be skipped
229 public void setSkipComments(boolean skipComments) {
230 this.skipComments = skipComments;
234 * Returns whether the reader is currently configured to skip string
237 * @return <code>true</code> if the reader is skipping strings and
238 * <code>false</code> otherwise
240 public boolean isSkippingStrings() {
245 * Configures the reader to skip strings.
247 * @param skipStrings Whether strings should be skipped
249 public void setSkipStrings(boolean skipStrings) {
250 this.skipStrings = skipStrings;
254 * Returns whether the reader is currently configured to skip whitespace.
256 * @return <code>true</code> if the reader is skipping whitespace and
257 * <code>false</code> otherwise
259 public boolean isSkippingWhitespace() {
260 return skipWhitespace;
264 * Configures the reader to skip whitespace.
266 * @param skipWhitespace Whether whitespace should be skipped
268 public void setSkipWhitespace(boolean skipWhitespace) {
269 this.skipWhitespace = skipWhitespace;
272 // Private Methods ---------------------------------------------------------
274 private int readBackwards() throws BadLocationException {
277 char current = document.getChar(offset);
280 if (skipComments && (offset > 1)) {
281 char next = document.getChar(offset - 1);
283 // a comment ends, advance to the comment start
285 skipUntilStartOfComment();
295 skipUntilStartOfString(current);
301 if (skipWhitespace && Character.isWhitespace(current)) {
311 private int readForwards() throws BadLocationException {
312 while (offset < end) {
313 char current = document.getChar(offset++);
316 if (skipComments && (offset < end)) {
317 char next = document.getChar(offset);
319 // a comment starts, advance to the comment end
321 skipUntilEndOfComment();
330 skipUntilEndOfString(current);
336 if (skipWhitespace && Character.isWhitespace(current)) {
347 private void skipUntilStartOfComment() throws BadLocationException {
349 char current = document.getChar(offset--);
350 if ((current == '*') && (0 <= offset)
351 && (document.getChar(offset) == '/')) {
357 private void skipUntilEndOfComment() throws BadLocationException {
358 while (offset < end) {
359 char current = document.getChar(offset++);
360 if (current == '*') {
362 && (document.getChar(offset) == '/')) {
370 private void skipUntilStartOfString(char delimiter)
371 throws BadLocationException {
373 char current = document.getChar(offset);
374 if (current == delimiter) {
375 if (!((0 <= offset) && document.getChar(offset - 1) == '\\')) {
383 private void skipUntilEndOfString(char delimiter)
384 throws BadLocationException {
385 while (offset < end) {
386 char current = document.getChar(offset++);
387 if (current == '\\') {
388 // ignore escaped characters
390 } else if (current == delimiter) {