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 }