/*
* Copyright 2014 Igor Maznitsa (http://www.igormaznitsa.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.igormaznitsa.prol.parser;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
/**
* The class describes a Prol reader which allows to read text data from an
* input stream and buffer it. As well it supports pushback operation.
*
* @author Igor Maznitsa (igor.maznitsa@igormaznitsa.com)
*/
public class ProlReader {
/**
* The constant shows the inside buffer size which is being used for backpush
* operations
*/
private static final int INSIDE_CHAR_BUFFER_SIZE = 64;
/**
* The text reader which is being used by the prol reader to read incomming
* text data
*/
private final Reader inReader;
/**
* Inside char buffer to temporary save text data
*/
private final char[] insideCharBuffer = new char[INSIDE_CHAR_BUFFER_SIZE];
/**
* The variable contains the inside char buffer pointer to show the current
* free position in the buffer
*/
private int insideCharBufferPointer = 0;
/**
* The variable contains the previous value of the string position indicator
*/
private int strPosPrev;
/**
* The variable contains the previous position of the line number indicator
*/
private int lineNumPrev;
/**
* The variable contains current value of the string position indicator
*/
private int strPos;
/**
* The variable contains current value of the line number indicator
*/
private int lineNum;
/**
* A constructor. To make a reader based on a String object.
*
* @param string A string object which will be used as the source for the
* reader, must not be null
*/
public ProlReader(final String string) {
this(new StringReader(string));
}
/**
* A constructor. To make a reader based on an input stream.
*
* @param inStream an input stream object which will be used as the source for
* the reader, must not be null
*/
public ProlReader(final InputStream inStream) {
this(new InputStreamReader(inStream));
}
/**
* A constructor. To make a reader based on a java reader object.
*
* @param reader a java reader object, must not be null
*/
public ProlReader(final Reader reader) {
inReader = reader;
strPos = 0;
lineNum = 1;
strPosPrev = strPos;
lineNumPrev = lineNum;
}
/**
* Read next char code from the reader
*
* @return the next char code or -1 if the stream end has been reached
* @throws IOException it will be thrown if there is any transport error
* during the operation
*/
public synchronized int read() throws IOException {
int ch;
if (insideCharBufferPointer > 0) {
ch = insideCharBuffer[--insideCharBufferPointer];
}
else {
ch = inReader.read();
}
strPosPrev = strPos;
lineNumPrev = lineNum;
if (ch == '\n') {
strPos = 0;
lineNum++;
}
else {
if (ch >= 0) {
strPos++;
}
}
return ch;
}
/**
* Push back the difference between an etalon string and a string buffer
* content.
*
* @param etalon an etalon string must not be null
* @param buffer a string buffer object, must not be null
*/
public synchronized void pushBufferDifference(final String etalon, final StringBuilder buffer) {
int chars = buffer.length() - etalon.length();
int pos = buffer.length() - 1;
while (chars > 0) {
char ch = buffer.charAt(pos--);
insideCharBuffer[insideCharBufferPointer++] = ch;
chars--;
strPos--;
if (strPos < 1) {
strPos = 1;
}
strPosPrev = strPos;
if (ch == '\n') {
lineNum--;
if (lineNum < 1) {
lineNum = 1;
}
lineNumPrev = lineNum;
}
}
}
/**
* Get the previous line number
*
* @return the previous line number
*/
public int getPrevLineNumber() {
return lineNumPrev;
}
/**
* Get the previous string position
*
* @return the previous string position
*/
public int getPrevStrPos() {
return strPosPrev;
}
/**
* Get the current line number
*
* @return the current line number
*/
public int getLineNumber() {
return lineNum;
}
/**
* Get the current string position
*
* @return the current string position
*/
public int getStrPos() {
return strPos;
}
/**
* Push a char back into the inside buffer to be read into the next read
* operation
*
* @param ch the char to be placed into the inside buffer
*/
public synchronized void pushCharBack(final char ch) {
insideCharBuffer[insideCharBufferPointer++] = ch;
if (ch == '\n') {
strPos = 1;
lineNum--;
if (lineNum <= 0) {
lineNum = 1;
}
}
else {
strPos--;
if (strPos <= 0) {
strPos = 1;
}
}
}
/**
* Close current reader
*
* @throws IOException it will be thrown if there is any error during the
* operation
*/
public synchronized void close() throws IOException {
inReader.close();
}
}