/*
* OpenClinica is distributed under the
* GNU Lesser General Public License (GNU LGPL).
* For details see: http://www.openclinica.org/license
*
* Copyright 2003-2008 Akaza Research
*/
package org.akaza.openclinica.logic.expressionTree;
import org.akaza.openclinica.exception.OpenClinicaSystemException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.IllegalFormatException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Krikor Krumlian
*
*/
public class TextIO {
protected final Logger logger = LoggerFactory.getLogger(getClass().getName());
/**
* The value returned by the peek() method when the input is at end-of-file. (The value of this constant is (char)0xFFFF.)
*/
public final char EOF = (char) 0xFFFF;
/**
* The value returned by the peek() method when the input is at end-of-line. The value of this constant is the character '\n'.
*/
public final char EOLN = '\n'; // The value returned by peek() when
// Matcher
private Matcher integerMatcher; // Used for reading integer numbers;
private Matcher floatMatcher; // Used for reading floating point
private Matcher dateMatcher; // Used for reading floating point
// Pattern
private final Pattern integerRegex = Pattern.compile("(\\+|-)?[0-9]+");
private final Pattern floatRegex = Pattern.compile("(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?");
private final Pattern dateRegex = Pattern.compile(ExpressionTreeHelper.yyyyMMddDashes);
private String buffer = null; // One line read from input.
private int pos = 0; // Position of next char in input line that has
/**
* Write a single value to the current output destination, using the default format and no extra spaces. This method will handle any type of parameter, even
* one whose type is one of the primitive types.
*/
public void put(Object x) {
logger.info("X : " + x);
}
/**
* Write a single value to the current output destination, using the default format and outputting at least minChars characters (with extra spaces added
* before the output value if necessary). This method will handle any type of parameter, even one whose type is one of the primitive types.
*
* @param x
* The value to be output, which can be of any type.
* @param minChars
* The minimum number of characters to use for the output. If x requires fewer then this number of characters, then extra spaces are added to the
* front of x to bring the total up to minChars. If minChars is less than or equal to zero, then x will be printed in the minumum number of
* spaces possible.
*/
public void put(Object x, int minChars) {
if (minChars <= 0){
if ( x!=null){
logger.debug(x.toString()) ;
}
}
else
logger.debug("%" + minChars + "s", x);
}
/**
* This is equivalent to put(x), followed by an end-of-line.
*/
public void putln(Object x) {
logger.info("X : " + x);
}
/**
* This is equivalent to put(x,minChars), followed by an end-of-line.
*/
public void putln(Object x, int minChars) {
put(x, minChars);
}
/**
* Write an end-of-line character to the current output destination.
*/
public void putln() {
logger.info("EOL");
}
/**
* Writes formatted output values to the current output destination. This method has the same function as System.out.printf(); the details of formatted
* output are not discussed here. The first parameter is a string that describes the format of the output. There can be any number of additional parameters;
* these specify the values to be output and can be of any type. This method will throw an IllegalArgumentException if the format string is null or if the
* format string is illegal for the values that are being output.
*/
public void putf(String format, Object... items) {
if (format == null)
throw new IllegalArgumentException("Null format string in TextIO.putf() method.");
try {
logger.debug(format, items);
} catch (IllegalFormatException e) {
throw new IllegalArgumentException("Illegal format string in TextIO.putf() method.");
}
}
// *************************** Input Methods
// *********************************
/**
* Test whether the next character in the current input source is an end-of-line. Note that this method does NOT skip whitespace before testing for
* end-of-line -- if you want to do that, call skipBlanks() first.
*/
public boolean eoln() {
return peek() == '\n';
}
/**
* Test whether the next character in the current input source is an end-of-file. Note that this method does NOT skip whitespace before testing for
* end-of-line -- if you want to do that, call skipBlanks() or skipWhitespace() first.
*/
public boolean eof() {
return peek() == EOF;
}
/**
* Reads the next character from the current input source. The character can be a whitespace character; compare this to the getChar() method, which skips
* over whitespace and returns the next non-whitespace character. An end-of-line is always returned as the character '\n', even when the actual end-of-line
* in the input source is something else, such as '\r' or "\r\n". This method will throw an IllegalArgumentException if the input is at end-of-file (which
* will not ordinarily happen if reading from standard input).
*/
public char getAnyChar() {
return readChar();
}
public String getAnyString(int x) {
return readString(x);
}
/**
* Returns the next character in the current input source, without actually removing that character from the input. The character can be a whitespace
* character and can be the end-of-file character (specfied by the constant TextIO.EOF).An end-of-line is always returned as the character '\n', even when
* the actual end-of-line in the input source is something else, such as '\r' or "\r\n". This method never causes an error.
*/
public char peek() {
return lookChar();
}
public String peek(int x) {
return lookString(x);
}
/**
* Skips over any whitespace characters, except for end-of-lines. After this method is called, the next input character is either an end-of-line, an
* end-of-file, or a non-whitespace character. This method never causes an error. (Ordinarly, end-of-file is not possible when reading from standard input.)
*/
public void skipBlanks() {
char ch = lookChar();
while (ch != EOF && ch != '\n' && Character.isWhitespace(ch)) {
readChar();
ch = lookChar();
}
}
/**
* Skips over any whitespace characters, including for end-of-lines. After this method is called, the next input character is either an end-of-file or a
* non-whitespace character. This method never causes an error. (Ordinarly, end-of-file is not possible when reading from standard input.)
*/
private void skipWhitespace() {
char ch = lookChar();
while (ch != EOF && Character.isWhitespace(ch)) {
readChar();
ch = lookChar();
}
}
/**
* Skips whitespace characters and then reads a value of type byte from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public byte getlnByte() {
byte x = getByte();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type short from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public short getlnShort() {
short x = getShort();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type int from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public int getlnInt() {
int x = getInt();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type long from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public long getlnLong() {
long x = getLong();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type float from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public float getlnFloat() {
float x = getFloat();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type double from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public double getlnDouble() {
double x = getDouble();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type char from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). Note that the value that is returned will be a non-whitespace character; compare this with the getAnyChar() method. When
* using standard IO, this will not produce an error. In other cases, an error can occur if an end-of-file is encountered.
*/
public char getlnChar() {
char x = getChar();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads a value of type boolean from input, discarding the rest of the current line of input (including the next
* end-of-line character, if any). When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
* <p>
* Legal inputs for a boolean input are: true, t, yes, y, 1, false, f, no, n, and 0; letters can be either upper case or lower case. One "word" of input is
* read, using the getWord() method, and it must be one of these; note that the "word" must be terminated by a whitespace character (or end-of-file).
*/
public boolean getlnBoolean() {
boolean x = getBoolean();
emptyBuffer();
return x;
}
/**
* Skips whitespace characters and then reads one "word" from input, discarding the rest of the current line of input (including the next end-of-line
* character, if any). A word is defined as a sequence of non-whitespace characters (not just letters!). When using standard IO, this will not produce an
* error. In other cases, an IllegalArgumentException will be thrown if an end-of-file is encountered.
*/
public String getlnWord() {
String x = getWord();
emptyBuffer();
return x;
}
/**
* This is identical to getln().
*/
public String getlnString() {
return getln();
}
/**
* Reads all the charcters from the current input source, up to the next end-of-line. The end-of-line is read but is not included in the return value. Any
* other whitespace characters on the line are retained, even if they occur at the start of input. The return value will be an empty string if there are no
* no characters before the end-of-line. When using standard IO, this will not produce an error. In other cases, an IllegalArgumentException will be thrown
* if an end-of-file is encountered.
*/
public String getln() {
StringBuffer s = new StringBuffer(100);
char ch = readChar();
while (ch != '\n') {
s.append(ch);
ch = readChar();
}
return s.toString();
}
/**
* Skips whitespace characters and then reads a value of type byte from input. Any additional characters on the current line of input are retained, and will
* be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public byte getByte() {
return (byte) readInteger(-128L, 127L);
}
/**
* Skips whitespace characters and then reads a value of type short from input. Any additional characters on the current line of input are retained, and
* will be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a
* legal value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public short getShort() {
return (short) readInteger(-32768L, 32767L);
}
/**
* Skips whitespace characters and then reads a value of type int from input. Any additional characters on the current line of input are retained, and will
* be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public int getInt() {
return (int) readInteger(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
/**
* Skips whitespace characters and then reads a value of type long from input. Any additional characters on the current line of input are retained, and will
* be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a legal
* value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public long getLong() {
return readInteger(Long.MIN_VALUE, Long.MAX_VALUE);
}
/**
* Skips whitespace characters and then reads a single non-whitespace character from input. Any additional characters on the current line of input are
* retained, and will be read by the next input operation. When using standard IO, this will not produce an error. In other cases, an
* IllegalArgumentException will be thrown if an end-of-file is encountered.
*/
public char getChar() {
skipWhitespace();
return readChar();
}
/**
* Skips whitespace characters and then reads a value of type float from input. Any additional characters on the current line of input are retained, and
* will be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a
* legal value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public float getFloat() {
float x = 0.0F;
while (true) {
String str = readRealString();
if (str == null) {
throw new OpenClinicaSystemException("OCRERR_0014");
// errorMessage("Floating point number not found.", "Real number
// in the range " + -Float.MAX_VALUE + " to " +
// Float.MAX_VALUE);
} else {
try {
x = Float.parseFloat(str);
} catch (NumberFormatException e) {
errorMessage("Illegal floating point input, " + str + ".", "Real number in the range " + -Float.MAX_VALUE + " to " + Float.MAX_VALUE);
continue;
}
if (Float.isInfinite(x)) {
errorMessage("Floating point input outside of legal range, " + str + ".", "Real number in the range " + -Float.MAX_VALUE + " to "
+ Float.MAX_VALUE);
continue;
}
break;
}
}
return x;
}
/**
* Skips whitespace characters and then reads a value of type double from input. Any additional characters on the current line of input are retained, and
* will be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a
* legal value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public String getDate() {
String str = readDateString();
return str;
}
/**
* Skips whitespace characters and then reads a value of type double from input. Any additional characters on the current line of input are retained, and
* will be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a
* legal value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
*/
public double getDouble() {
double x = 0.0;
while (true) {
String str = readRealString();
if (str == null) {
errorMessage("Floating point number not found.", "Real number in the range " + -Double.MAX_VALUE + " to " + Double.MAX_VALUE);
} else {
try {
x = Double.parseDouble(str);
} catch (NumberFormatException e) {
errorMessage("Illegal floating point input, " + str + ".", "Real number in the range " + -Double.MAX_VALUE + " to " + Double.MAX_VALUE);
continue;
}
if (Double.isInfinite(x)) {
errorMessage("Floating point input outside of legal range, " + str + ".", "Real number in the range " + -Double.MAX_VALUE + " to "
+ Double.MAX_VALUE);
continue;
}
break;
}
}
return x;
}
/**
* Skips whitespace characters and then reads one "word" from input. Any additional characters on the current line of input are retained, and will be read
* by the next input operation. A word is defined as a sequence of non-whitespace characters (not just letters!). When using standard IO, this will not
* produce an error. In other cases, an IllegalArgumentException will be thrown if an end-of-file is encountered.
*/
public String getDoubleQuoteWord() {
skipWhitespace();
StringBuffer str = new StringBuffer(50);
char ch = lookChar();
int quoteCount = 0;
while (ch != EOF && quoteCount < 2) {
if (Character.toString(ch).equals("\"")) {
quoteCount++;
}
str.append(readChar());
ch = lookChar();
}
return str.toString().replaceAll("\"", "");
}
/**
* Skips whitespace characters and then reads one "word" from input. Any additional characters on the current line of input are retained, and will be read
* by the next input operation. A word is defined as a sequence of non-whitespace characters (not just letters!). When using standard IO, this will not
* produce an error. In other cases, an IllegalArgumentException will be thrown if an end-of-file is encountered.
*/
public String getWord() {
skipWhitespace();
StringBuffer str = new StringBuffer(50);
char ch = lookChar();
//while (ch == EOF || !Character.isWhitespace(ch)) {
while (ch == EOF || !Character.isWhitespace(ch) && ch != ')') {
str.append(readChar());
ch = lookChar();
}
return str.toString();
}
/**
* Skips whitespace characters and then reads a value of type boolean from input. Any additional characters on the current line of input are retained, and
* will be read by the next input operation. When using standard IO, this will not produce an error; the user will be prompted repeatedly for input until a
* legal value is input. In other cases, an IllegalArgumentException will be thrown if a legal value is not found.
* <p>
* Legal inputs for a boolean input are: true, t, yes, y, 1, false, f, no, n, and 0; letters can be either upper case or lower case. One "word" of input is
* read, using the getWord() method, and it must be one of these; note that the "word" must be terminated by a whitespace character (or end-of-file).
*/
public boolean getBoolean() {
boolean ans = false;
while (true) {
String s = getWord();
if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("t") || s.equalsIgnoreCase("yes") || s.equalsIgnoreCase("y") || s.equals("1")) {
ans = true;
break;
} else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("f") || s.equalsIgnoreCase("no") || s.equalsIgnoreCase("n") || s.equals("0")) {
ans = false;
break;
} else
errorMessage("Illegal boolean input value.", "one of: true, false, t, f, yes, no, y, n, 0, or 1");
}
return ans;
}
private String readDateString() { // read chars from input
// following syntax of real
// numbers
skipWhitespace();
if (lookChar() == EOF)
return null;
if (dateMatcher == null)
dateMatcher = dateRegex.matcher(buffer);
dateMatcher.region(pos, buffer.length());
if (dateMatcher.lookingAt()) {
String str = dateMatcher.group();
pos = dateMatcher.end();
return str;
} else
return null;
}
private String readRealString() { // read chars from input
// following syntax of real
// numbers
skipWhitespace();
if (lookChar() == EOF)
return null;
if (floatMatcher == null)
floatMatcher = floatRegex.matcher(buffer);
floatMatcher.region(pos, buffer.length());
if (floatMatcher.lookingAt()) {
String str = floatMatcher.group();
pos = floatMatcher.end();
return str;
} else
return null;
}
private String readIntegerString() { // read chars from input
// following syntax of integers
skipWhitespace();
if (lookChar() == EOF)
return null;
if (integerMatcher == null)
integerMatcher = integerRegex.matcher(buffer);
integerMatcher.region(pos, buffer.length());
if (integerMatcher.lookingAt()) {
String str = integerMatcher.group();
pos = integerMatcher.end();
return str;
} else
return null;
}
private long readInteger(long min, long max) { // read long
// integer, limited
// to specified
// range
long x = 0;
while (true) {
String s = readIntegerString();
if (s == null) {
errorMessage("Integer value not found in input.", "Integer in the range " + min + " to " + max);
} else {
String str = s.toString();
try {
x = Long.parseLong(str);
} catch (NumberFormatException e) {
errorMessage("Illegal integer input, " + str + ".", "Integer in the range " + min + " to " + max);
continue;
}
if (x < min || x > max) {
errorMessage("Integer input outside of legal range, " + str + ".", "Integer in the range " + min + " to " + max);
continue;
}
break;
}
}
return x;
}
private void errorMessage(String message, String expecting) { // Report
logger.info("ERROR");
}
private char lookChar() { // return next character from input
if (buffer == null || pos > buffer.length())
return EOF;
else if (pos == buffer.length())
return '\n';
else
return buffer.charAt(pos);
}
private String lookString(int x) { // return next String from
// input
if (buffer == null || pos > buffer.length() || pos + x > buffer.length())
return null;
else if (pos == buffer.length())
return "\n";
else
return buffer.substring(pos, pos + x);
}
private char readChar() { // return and discard next character
// from input
char ch = lookChar();
if (buffer == null) {
throw new IllegalArgumentException("Attempt to read past end-of-string");
}
pos++;
return ch;
}
private String readString(int x) { // return and discard next
// character
// from input
String str = lookString(x);
if (buffer == null) {
throw new IllegalArgumentException("Attempt to read past end-of-string");
}
pos += x;
return str;
}
/*
* private void fillBuffer() { // Wait for user to type a line and // press return, try { buffer = in.readLine(); } catch (Exception e) { if
* (readingStandardInput) throw new IllegalArgumentException("Error while reading standard input???"); else if (inputFileName != null) throw new
* IllegalArgumentException("Error while attempting to read from file \"" + inputFileName + "\"."); else throw new IllegalArgumentException("Errow while
* attempting to read form an input stream."); } pos = 0; floatMatcher = null; integerMatcher = null; }
*/
public void fillBuffer(String expression) { // Wait for user to type a line
// and
// press return,
try {
buffer = expression;
} catch (Exception e) {
throw new IllegalArgumentException("Errow while attempting to read form an input stream.");
}
pos = 0;
floatMatcher = null;
integerMatcher = null;
}
private void emptyBuffer() { // discard the rest of the current line
// of input
buffer = null;
}
} // end of class TextIO