/******************************************************************************* * Copyright (c) 2006, 2012 Wind River Systems, Inc. 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: * Anton Leherbauer (Wind River Systems) - initial API and implementation * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.formatter.scanner; import java.io.CharArrayReader; import java.io.Reader; import org.eclipse.cdt.internal.core.CharOperation; /** * A scanner operating on a character array and allowing to reposition the scanner. * * @since 4.0 */ public class Scanner extends SimpleScanner { public char[] source; public int eofPosition; public int startPosition; public Scanner() { setReuseToken(true); setSplitPreprocessor(false); } @Override protected void init(Reader reader, String filename) { // not allowed throw new UnsupportedOperationException(); } /** * Set the source text as character array. * * @param source the source text */ public void setSource(char[] source) { this.source= source; fContext= new ScannerContext().initialize(new CharArrayReader(source)); startPosition= -1; eofPosition= source.length; } /** * Reset scanner to given inclusive start and end offsets * @param start inclusive start offset * @param end exclusive end offset */ public void resetTo(int start, int end) { Reader reader; if (end >= source.length) { reader= new CharArrayReader(source); } else { reader= new CharArrayReader(source, 0, Math.min(source.length, end)); } fContext= new ScannerContext().initialize(reader, start); startPosition= start; if (source != null && source.length < end) { eofPosition = source.length; } else { eofPosition = end; } } /** * Get the start offset of the current token. * @return the start offset of the current token */ public int getCurrentTokenStartPosition() { return fCurrentToken.offset; } /** * Get the inclusive end offset of the current token. * @return the inclusive end offset of the current token */ public int getCurrentTokenEndPosition() { return getCurrentPosition() - 1; } /** * Get the current scanner offset. * @return the current scanner offset */ public int getCurrentPosition() { return fContext.getOffset() - fContext.undoStackSize(); } /** * Returns {@code true} if the scanner has reached the end of file. */ public final boolean atEnd() { return getCurrentPosition() >= eofPosition; } /** * Get the next character. * @return the next character */ public int getNextChar() { return getChar(); } /** * Move to next character iff it is equal to the given expected character. * If the characters do not match, the scanner does not move forward. * * @param c the expected character * @return <code>true</code> if the next character was the expected character */ public boolean getNextChar(char c) { if (c == getChar()) { return true; } ungetChar(c); return false; } /** * Returns the next character without moving the pointer. */ public int peekNextChar() { int c = getChar(); ungetChar(c); return c; } /** * Set current scanner offset to given offset. * * @param nextCharacterStart the desired scanner offset */ public void setCurrentPosition(int nextCharacterStart) { int currentPos= getCurrentPosition(); int diff= currentPos - nextCharacterStart; if (diff < 0) { do { getChar(); ++diff; } while (diff < 0); } else if (diff == 0) { // no-op } else if (diff > fTokenBuffer.length()) { resetTo(nextCharacterStart, source.length); } else /* if (diff <= fTokenBuffer.length()) */ { while (diff > 0) { if (fTokenBuffer.length() > 0) { ungetChar(fTokenBuffer.charAt(fTokenBuffer.length() - 1)); } --diff; } } } /** * Get the text of the current token as a character array. * @return the token text */ public char[] getCurrentTokenSource() { return fCurrentToken.getText().toCharArray(); } /** * Get the next token as token type constant. * * @return the next token type */ public int getNextToken() { Token token= nextToken(); if (token == null) { return -1; } return token.type; } /** * For debugging purposes. */ @Override public String toString() { if (this.startPosition == this.source.length) return "EOF\n\n" + new String(this.source); //$NON-NLS-1$ if (this.getCurrentPosition() > this.source.length) return "behind the EOF\n\n" + new String(this.source); //$NON-NLS-1$ char front[] = new char[this.startPosition]; System.arraycopy(this.source, 0, front, 0, this.startPosition); int middleLength = (this.getCurrentPosition() - 1) - this.startPosition + 1; char middle[]; if (middleLength > -1) { middle = new char[middleLength]; System.arraycopy( this.source, this.startPosition, middle, 0, middleLength); } else { middle = CharOperation.NO_CHAR; } char end[] = new char[this.source.length - (this.getCurrentPosition() - 1)]; System.arraycopy( this.source, (this.getCurrentPosition() - 1) + 1, end, 0, this.source.length - (this.getCurrentPosition() - 1) - 1); return new String(front) + "\n===============================\nStarts here -->" //$NON-NLS-1$ + new String(middle) + "<-- Ends here\n===============================\n" //$NON-NLS-1$ + new String(end); } }