001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * Sonar is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.squid.text;
021
022 import java.io.BufferedReader;
023 import java.io.CharArrayWriter;
024 import java.io.IOException;
025 import java.io.Reader;
026 import java.io.StringReader;
027
028 import org.sonar.squid.api.AnalysisException;
029
030 public class CodeReader {
031
032 private final Reader reader;
033 private int HISTORY_SIZE = 3;
034 private int[] lastChars = new int[HISTORY_SIZE];
035
036 public CodeReader(Reader reader) {
037 this.reader = new BufferedReader(reader);
038 for (int i = 0; i < lastChars.length; i++) {
039 lastChars[i] = -1;
040 }
041 }
042
043 public CodeReader(String code) {
044 this(new StringReader(code));
045 }
046
047 private int read() throws IOException {
048 if (!reader.ready()) {
049 return -1;
050 }
051 return reader.read();
052 }
053
054 public final void mark(int readAheadLimit) throws IOException {
055 if (reader.markSupported()) {
056 throw new AnalysisException("Mark are not supported on provided Reader.");
057 }
058 reader.mark(readAheadLimit);
059 }
060
061 public final int lastChar() {
062 return lastChars[0];
063 }
064
065 public final int peek() {
066 try {
067 reader.mark(1);
068 int nextChar = read();
069 reader.reset();
070 return nextChar;
071 } catch (IOException e) {
072 throw new AnalysisException("Unable to read on input stream.", e);
073 }
074 }
075
076 public final int pop() {
077 try {
078 setLastChar(read());
079 return lastChar();
080 } catch (IOException e) {
081 throw new AnalysisException("Unable to read on input stream.", e);
082 }
083 }
084
085 private void setLastChar(int read) {
086 for (int i = lastChars.length - 1; i > 0; i--) {
087 lastChars[i] = lastChars[i - 1];
088 }
089 lastChars[0] = read;
090
091 }
092
093 public String readTo(EndTokenMatcher matcher) {
094 CharArrayWriter result = new CharArrayWriter();
095 result.append((char) pop());
096 while (!matcher.match(peek()) && peek() != -1) {
097 result.append((char) pop());
098 }
099 return result.toString();
100 }
101
102 public void close() {
103 try {
104 reader.close();
105 } catch (IOException e) {
106 throw new AnalysisException("Unable to close the reader on source code.", e);
107 }
108 }
109
110 public char[] peek(int index) {
111 try {
112 char[] result = new char[index];
113 reader.mark(index);
114 reader.read(result, 0, index);
115 reader.reset();
116 return result;
117 } catch (IOException e) {
118 throw new AnalysisException("Unable to read on input stream.", e);
119 }
120 }
121
122 public int lastChar(int index) {
123 return lastChars[index];
124 }
125 }