/******************************************************************************* * Copyright (c) 2004, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jst.jsp.ui.internal.text; import java.io.IOException; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jst.jsp.ui.internal.derived.SingleCharReader; /** * Reads from a document either forwards or backwards. May be configured to * skip comments and strings. * * Copied from org.eclipse.jdt.internal.ui.text so we don't have to * depend on the org.eclipse.jdt.ui plugin. * * No modifications were made. */ class JavaCodeReader extends SingleCharReader { /** The EOF character */ public static final int EOF = -1; private boolean fSkipComments = false; private boolean fSkipStrings = false; private boolean fForward = false; private IDocument fDocument; private int fOffset; private int fEnd = -1; private int fCachedLineNumber = -1; private int fCachedLineOffset = -1; public JavaCodeReader() { } /** * Returns the offset of the last read character. Should only be called after read has been called. */ public int getOffset() { return fForward ? fOffset - 1 : fOffset; } public void configureForwardReader(IDocument document, int offset, int length, boolean skipComments, boolean skipStrings) throws IOException { fDocument = document; fOffset = offset; fSkipComments = skipComments; fSkipStrings = skipStrings; fForward = true; fEnd = Math.min(fDocument.getLength(), fOffset + length); } public void configureBackwardReader(IDocument document, int offset, boolean skipComments, boolean skipStrings) throws IOException { fDocument = document; fOffset = offset; fSkipComments = skipComments; fSkipStrings = skipStrings; fForward = false; try { fCachedLineNumber = fDocument.getLineOfOffset(fOffset); } catch (BadLocationException x) { throw new IOException(x.getMessage()); } } /* * @see Reader#close() */ public void close() throws IOException { fDocument = null; } /* * @see SingleCharReader#read() */ public int read() throws IOException { try { return fForward ? readForwards() : readBackwards(); } catch (BadLocationException x) { throw new IOException(x.getMessage()); } } private void gotoCommentEnd() throws BadLocationException { while (fOffset < fEnd) { char current = fDocument.getChar(fOffset++); if (current == '*') { if (fOffset < fEnd && fDocument.getChar(fOffset) == '/') { ++fOffset; return; } } } } private void gotoStringEnd(char delimiter) throws BadLocationException { while (fOffset < fEnd) { char current = fDocument.getChar(fOffset++); if (current == '\\') { // ignore escaped characters ++fOffset; } else if (current == delimiter) { return; } } } private void gotoLineEnd() throws BadLocationException { int line = fDocument.getLineOfOffset(fOffset); fOffset = fDocument.getLineOffset(line + 1); } private int readForwards() throws BadLocationException { while (fOffset < fEnd) { char current = fDocument.getChar(fOffset++); switch (current) { case '/' : if (fSkipComments && fOffset < fEnd) { char next = fDocument.getChar(fOffset); if (next == '*') { // a comment starts, advance to the comment end ++fOffset; gotoCommentEnd(); continue; } else if (next == '/') { // '//'-comment starts, advance to the line end gotoLineEnd(); continue; } } return current; case '"' : case '\'' : if (fSkipStrings) { gotoStringEnd(current); continue; } return current; } return current; } return EOF; } private void handleSingleLineComment() throws BadLocationException { int line = fDocument.getLineOfOffset(fOffset); if (line < fCachedLineNumber) { fCachedLineNumber = line; fCachedLineOffset = fDocument.getLineOffset(line); int offset = fOffset; while (fCachedLineOffset < offset) { char current = fDocument.getChar(offset--); if (current == '/' && fCachedLineOffset <= offset && fDocument.getChar(offset) == '/') { fOffset = offset; return; } } } } private void gotoCommentStart() throws BadLocationException { while (0 < fOffset) { char current = fDocument.getChar(fOffset--); if (current == '*' && 0 <= fOffset && fDocument.getChar(fOffset) == '/') return; } } private void gotoStringStart(char delimiter) throws BadLocationException { while (0 < fOffset) { char current = fDocument.getChar(fOffset); if (current == delimiter) { if (!(0 <= fOffset && fDocument.getChar(fOffset - 1) == '\\')) return; } --fOffset; } } private int readBackwards() throws BadLocationException { while (0 < fOffset) { --fOffset; handleSingleLineComment(); char current = fDocument.getChar(fOffset); switch (current) { case '/' : if (fSkipComments && fOffset > 1) { char next = fDocument.getChar(fOffset - 1); if (next == '*') { // a comment ends, advance to the comment start fOffset -= 2; gotoCommentStart(); continue; } } return current; case '"' : case '\'' : if (fSkipStrings) { --fOffset; gotoStringStart(current); continue; } return current; } return current; } return EOF; } }