intial source from ttp://www.sf.net/projects/wdte
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.css.core / src / net / sourceforge / phpeclipse / css / core / internal / text / CssCodeReader.java
diff --git a/archive/net.sourceforge.phpeclipse.css.core/src/net/sourceforge/phpeclipse/css/core/internal/text/CssCodeReader.java b/archive/net.sourceforge.phpeclipse.css.core/src/net/sourceforge/phpeclipse/css/core/internal/text/CssCodeReader.java
new file mode 100644 (file)
index 0000000..0672123
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (c) 2003-2004 Christopher Lenz and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     Christopher Lenz - initial API and implementation
+ * 
+ * $Id: CssCodeReader.java,v 1.1 2004-09-02 18:07:13 jsurfer Exp $
+ */
+
+package net.sourceforge.phpeclipse.css.core.internal.text;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+
+/**
+ * 
+ */
+public class CssCodeReader extends Reader {
+
+       // Constants ---------------------------------------------------------------
+
+       /**
+        * Constant for configuring a reader to read the document backwards.
+        */
+       public static final int BACKWARD = -1;
+       
+       /**
+        * Constant for configuring a reader to read the document forwards.
+        */
+       public static final int FORWARD = 1;
+
+       // Instance Variables ------------------------------------------------------
+
+       /**
+        * The document to read. Is <code>null</code> when the reader is closed.
+        */
+       private IDocument document;
+
+       /**
+        * The direction in which the document should be read. Can be either
+        * {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD}. 
+        */
+       private int direction;
+
+       /**
+        * The offset at which to start reading.
+        */
+       private int offset;
+       
+       /**
+        * The offset at which to end reading.
+        */
+       private int end = -1;
+       
+       /**
+        * Whether comments should be skipped.
+        */
+       private boolean skipComments;
+       
+       /**
+        * Whether string literals should be skipped.
+        */
+       private boolean skipStrings;
+       
+       /**
+        * Whether whitespace characters should be skipped.
+        */
+       private boolean skipWhitespace;
+       
+       // Constructors ------------------------------------------------------------
+
+       /**
+        * Constructor.
+        * 
+        * @param document the document to read
+        * @param offset the offset at which to start reading
+        */
+       public CssCodeReader(IDocument document, int offset) {
+               this(document, offset, document.getLength() - offset, FORWARD);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param document the document to read
+        * @param offset the offset at which to start reading
+        * @param length the number of characters to read at most
+        */
+       public CssCodeReader(IDocument document, int offset, int length) {
+               this(document, offset, length, FORWARD);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param document the document to read
+        * @param offset the offset at which to start reading
+        * @param length the number of characters to read at most
+        * @param direction the reading direction (either
+        *        {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD})
+        */
+       public CssCodeReader(IDocument document, int offset, int length,
+               int direction) {
+               this(document, offset, length, direction, true, false, false);
+       }
+
+       /**
+        * Constructor.
+        * 
+        * @param document the document to read
+        * @param offset the offset at which to start reading
+        * @param length the number of characters to read at most
+        * @param direction the reading direction (either
+        *        {@link CssCodeReader#BACKWARD} or {@link CssCodeReader#FORWARD})
+        * @param skipComments whether the reader should skip comments
+        * @param skipStrings whether the reader should skip strings
+        * @param skipWhitespace whether the reader should skip whitespace
+        */
+       public CssCodeReader(IDocument document, int offset, int length,
+               int direction, boolean skipComments, boolean skipStrings,
+               boolean skipWhitespace) {
+               if ((direction != BACKWARD) && (direction != FORWARD)) {
+                       throw new IllegalArgumentException();
+               }
+               if ((offset < 0) || (offset > document.getLength())) {
+                       throw new IllegalArgumentException();
+               }
+               this.document = document;
+               this.offset = offset;
+               this.direction = direction;
+               if (direction == FORWARD) {
+                       end = Math.min(document.getLength(), offset + length);
+               } else {
+                       end = Math.max(0, offset - length);
+               }
+               this.skipComments = skipComments;
+               this.skipStrings = skipStrings;
+               this.skipWhitespace = skipWhitespace;
+       }
+
+       // Reader Implementation ---------------------------------------------------
+
+       /**
+        * @see Reader#close()
+        */
+       public void close() {
+               document = null;
+       }
+       
+       /**
+        * @see Reader#read(char[], int, int)
+        */
+       public int read(char[] cbuf, int off, int len) throws IOException {
+               for (int i = off; i < off + len; i++) {
+                       int c = read();
+                       if (c == -1) {
+                               if (i == off) {
+                                       return -1;
+                               } else {
+                                       return i - off;
+                               }
+                       }
+                       cbuf[i] = (char) c;
+               }
+               return len;
+       }
+
+       /**
+        * @see Reader#read()
+        */
+       public int read() throws IOException {
+               if (document == null) {
+                       throw new IllegalStateException();
+               }
+               try {
+                       if (direction == FORWARD) {
+                               return readForwards();
+                       } else {
+                               return readBackwards();
+                       }
+               } catch (BadLocationException ble) {
+                       throw new IOException(ble.getMessage());
+               }
+       }
+
+       // Public Methods ----------------------------------------------------------
+
+       /**
+        * Returns the document that is being read.
+        * 
+        * @return The document
+        */
+       public IDocument getDocument() {
+               return document;
+       }
+
+       /**
+        * Returns the offset of the last read character. Should only be called 
+        * after read has been called.
+        * 
+        * @return The offset of the last read character
+        */
+       public int getOffset() {
+               return (direction == FORWARD) ? offset - 1 : offset;
+       }
+       
+       /**
+        * Returns whether the reader is currently configured to skip comments.
+        * 
+        * @return <code>true</code> if the reader is skipping comments and
+        *         <code>false</code> otherwise
+        */
+       public boolean isSkippingComments() {
+               return skipComments;
+       }
+
+       /**
+        * Configures the reader to skip comment blocks.
+        * 
+        * @param skipComments Whether comments should be skipped
+        */
+       public void setSkipComments(boolean skipComments) {
+               this.skipComments = skipComments;
+       }
+
+       /**
+        * Returns whether the reader is currently configured to skip string
+        * literals.
+        * 
+        * @return <code>true</code> if the reader is skipping strings and
+        *         <code>false</code> otherwise
+        */
+       public boolean isSkippingStrings() {
+               return skipStrings;
+       }
+
+       /**
+        * Configures the reader to skip strings.
+        * 
+        * @param skipStrings Whether strings should be skipped
+        */
+       public void setSkipStrings(boolean skipStrings) {
+               this.skipStrings = skipStrings;
+       }
+
+       /**
+        * Returns whether the reader is currently configured to skip whitespace.
+        * 
+        * @return <code>true</code> if the reader is skipping whitespace and
+        *         <code>false</code> otherwise
+        */
+       public boolean isSkippingWhitespace() {
+               return skipWhitespace;
+       }
+
+       /**
+        * Configures the reader to skip whitespace.
+        * 
+        * @param skipWhitespace Whether whitespace should be skipped
+        */
+       public void setSkipWhitespace(boolean skipWhitespace) {
+               this.skipWhitespace = skipWhitespace;
+       }
+
+       // Private Methods ---------------------------------------------------------
+
+       private int readBackwards() throws BadLocationException {
+               while (offset > 0) {
+                       offset--;
+                       char current = document.getChar(offset);
+                       switch (current) {
+                               case '/': {
+                                       if (skipComments && (offset > 1)) {
+                                               char next = document.getChar(offset - 1);
+                                               if (next == '*') {
+                                                       // a comment ends, advance to the comment start
+                                                       offset -= 2;
+                                                       skipUntilStartOfComment();
+                                                       continue;
+                                               }
+                                       }
+                                       break;
+                               }
+                               case '"':
+                               case '\'': {
+                                       if (skipStrings) {
+                                               offset--;
+                                               skipUntilStartOfString(current);
+                                               continue;
+                                       }
+                                       break;
+                               }
+                               default: {
+                                       if (skipWhitespace && Character.isWhitespace(current)) {
+                                               continue;
+                                       }
+                               }
+                       }
+                       return current;
+               }
+               return -1;
+       }
+
+       private int readForwards() throws BadLocationException {
+               while (offset < end) {
+                       char current = document.getChar(offset++);
+                       switch (current) {
+                               case '/': {
+                                       if (skipComments && (offset < end)) {
+                                               char next = document.getChar(offset);
+                                               if (next == '*') {
+                                                       // a comment starts, advance to the comment end
+                                                       offset++;
+                                                       skipUntilEndOfComment();
+                                                       continue;
+                                               }
+                                       }
+                                       break;
+                               }
+                               case '"':
+                               case '\'': {
+                                       if (skipStrings) {
+                                               skipUntilEndOfString(current);
+                                               continue;
+                                       }
+                                       break;
+                               }
+                               default: {
+                                       if (skipWhitespace && Character.isWhitespace(current)) {
+                                               offset++;
+                                               continue;
+                                       }
+                               }
+                       }
+                       return current;
+               }
+               return -1;
+       }
+
+       private void skipUntilStartOfComment() throws BadLocationException {
+               while (offset > 0) {
+                       char current = document.getChar(offset--);
+                       if ((current == '*') && (0 <= offset)
+                        && (document.getChar(offset) == '/')) {
+                               return;
+                       }
+               }
+       }
+
+       private void skipUntilEndOfComment() throws BadLocationException {
+               while (offset < end) {
+                       char current = document.getChar(offset++);
+                       if (current == '*') {
+                               if ((offset < end)
+                                && (document.getChar(offset) == '/')) {
+                                       offset++;
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       private void skipUntilStartOfString(char delimiter)
+               throws BadLocationException {
+               while (offset > 0) {
+                       char current = document.getChar(offset);
+                       if (current == delimiter) {
+                               if (!((0 <= offset) && document.getChar(offset - 1) == '\\')) {
+                                       return;
+                               }
+                       }
+                       offset--;
+               }
+       }
+
+       private void skipUntilEndOfString(char delimiter)
+               throws BadLocationException {
+               while (offset < end) {
+                       char current = document.getChar(offset++);
+                       if (current == '\\') {
+                               // ignore escaped characters
+                               offset++;
+                       } else if (current == delimiter) {
+                               return;
+                       }
+               }
+       }
+
+}