
org.cip4.jdflib.cformat.ScanfReader Maven / Gradle / Ivy
Show all versions of JDFLibJ Show documentation
/*
* Copyright John E. Lloyd, 2000. All rights reserved. Permission
* to use, copy, and modify, without fee, is granted for non-commercial
* and research purposes, provided that this copyright notice appears
* in all copies.
*
* This software is distributed "as is", without any warranty, including
* any implied warranty of merchantability or fitness for a particular
* use. The authors assume no responsibility for, and shall not be liable
* for, any special, indirect, or consequential damages, or any damages
* whatsoever, arising out of or in connection with the use of this
* software.
*/
package org.cip4.jdflib.cformat;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
/**
* A Reader which implements C scanf functionality. Once created, an application can read various primitive types from the underlying stream using various scan
* methods that implement scanf type input formatting.
*
*
* There are scan methods to read float, double, long, int, char, char[], and String. The methods take as an argument either a format string, a pre-allocated ScanfFormat
* object which is created from a format string, or no argument (implying a default format). The format string is modeled after that accepted by the C scanf() methodName,
* and is described in the documentation for the class ScanfFormat.
*
*
* Because Java does not permit variable-length argument lists, only one primitive type may be returned per method, and the format used may contain only one conversion
* specification (which must be appropriate to the type being scanned).
*
*
* Input errors in the underlying Reader result in a java.io.IOException being thrown, while a java.io.EOFException is thrown if the end of input is reached
* before the scan can complete successfully. If the input does not match the specified format, then a ScanfMatchException is thrown. In the event of a match error,
* scanning stops at the first character from which it can be determined that the match will fail. This character is remembered by the stream (see the discussion of the look-ahead
* character, below) and will be the first character seen by the next scan or read method which is called. Finally, an invalid format string (or
* ScanfFormat object) will trigger an InvalidArgumentException.
*
*
* The class keeps track of the current line number (accessible with the methods getLineNumber and setLineNumber), as well as the number of characters which have
* been consumed (accesible with the methods getCharNumber and setCharNumber).
*
*
* The class usually keeps one character of look-ahead which has been read from the underlying reader but not yet consumed by any scan method. If the underlying reader is used
* later in some other capacity, this look-ahead character may have to be taken into account. If a look-ahead character is actually being stored, the lookAheadCharValid
* method will return true, and the look-ahead character itself can then be obtained using the getLookAheadChar method. The look-ahead character can be cleared
* using the clearLookAheadChar method.
*
* @deprecated use Scanner
*/
@Deprecated
public class ScanfReader extends Reader
{
// ~ Static fields/initializers
// /////////////////////////////////////////////
private static String hexChars = "0123456789abcdefABCDEF";
private static String octChars = "01234567";
private static final int BUFSIZE = 1024;
private static ScanfFormat defaultDoubleFmt = new ScanfFormat("%f");
private static ScanfFormat defaultIntFmt = new ScanfFormat("%i");
private static ScanfFormat defaultDecFmt = new ScanfFormat("%d");
private static ScanfFormat defaultHexFmt = new ScanfFormat("%x");
private static ScanfFormat defaultOctFmt = new ScanfFormat("%o");
private static ScanfFormat defaultStringFmt = new ScanfFormat("%s");
private static ScanfFormat defaultCharFmt = new ScanfFormat("%c");
// ~ Instance fields
// ////////////////////////////////////////////////////////
private int bcnt;
private final char[] buffer;
private int charCnt = 0;
private int curChar;
private boolean curCharValid = false;
private int lastChar;
private int lineCnt = 1;
private Reader reader = null;
private boolean spacesCStandardFlag = true;
// ~ Constructors
// ///////////////////////////////////////////////////////////
/**
* Create a new ScanfReader from the given reader.
*
* @param reader Underlying Reader
*/
public ScanfReader(final Reader in)
{
super();
reader = in;
curCharValid = false;
charCnt = 0;
lineCnt = 1;
curChar = 0;
lastChar = 0;
// XXX XXX XXX fixed size buffer is a big hack
buffer = new char[BUFSIZE];
bcnt = 0;
}
// ~ Methods
// ////////////////////////////////////////////////////////////////
/**
* Clears the look-ahead character.
*/
public void clearLookAheadChar()
{
curCharValid = false;
}
/**
* Closes the stream.
*
* @throws IOException An I/O error occurred
*/
@Override
public void close() throws IOException
{
reader.close();
}
/**
* Gets the current character number (equal to the number of characters that have been consumed by the stream).
*
* @return Current character number
* @see ScanfReader#setCharNumber
*/
public int getCharNumber()
{
return charCnt;
}
/**
* Gets the current line number. The initial value (when the Reader is created) is 1. A new line is recorded upon reading a carriage return, a line feed, or a carriage return
* immediately followed by a line feed.
*
* @return Current line number
* @see ScanfReader#setLineNumber
*/
public int getLineNumber()
{
return lineCnt;
}
/**
* Returns the look-ahead character.
*
* @return Look-ahead character, -1 if EOF has been reached, or 0 if no look-ahead character is being stored.
*/
public int getLookAheadChar()
{
int i = 0;
if (curCharValid)
{
i = curChar;
}
return i;
}
/**
* Returns whether or not a look-ahead character is currently begin stored.
*
* @return True if a look-ahead character is being stored.
*/
public boolean lookAheadCharValid()
{
return curCharValid;
}
/**
* Reads characters into a portion of a character array. The method will block until input is available, an I/O error occurs, or the end of the stream is reached.
*
* @param cbuf Buffer to write characters into
* @param off Offset to start writing at
* @param len Number of characters to read
* @return The number of characters read, or -1 if the end of the stream is reached.
* @throws IOException An I/O error occurred
*/
@Override
public int read(final char[] cbuf, final int off, final int len) throws IOException
{
int offLocal = off;
int lenLocal = len;
int n;
int c;
int n0 = 0;
if (curCharValid)
{
consumeChar();
if (curChar != -1)
{
cbuf[offLocal++] = (char) curChar;
lenLocal--;
n0 = 1;
}
else
{
return -1;
}
}
if (lenLocal > 0)
{
n = reader.read(cbuf, offLocal, lenLocal);
}
else
{
return n0;
}
if (n == -1)
{
return -1;
}
for (int i = 0; i < n; i++)
{
c = cbuf[offLocal + i];
if ((c == '\r') || ((c == '\n') && (lastChar != '\r')))
{
lineCnt++;
}
lastChar = c;
}
charCnt += n;
return n + n0;
}
/**
* Scan and return a single character, using the default format string "%c".
*
* @param s Format string
* @return Scanned character
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanChar(String)
*/
public char scanChar() throws IOException, ScanfMatchException
{
char val = 0;
try
{
val = scanChar(defaultCharFmt);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a single character.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 'c' or '['. If
* the conversion character is '[', then each character scanned must match the sequence specified between the '[' and the closing ']' (see the documentation for
* ScanfFormat).
*
*
* White space preceding the character is not skipped.
*
* @param s Format string
* @return Scanned character
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public char scanChar(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanChar(new ScanfFormat(s));
}
/**
* Scan and return a single character, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned character
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanChar(String)
*/
public char scanChar(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
char value = 0;
checkTypeAndScanPrefix(fmt, "c[");
initChar();
if (curChar == -1)
{
throw new EOFException("EOF");
}
value = (char) curChar;
if ((fmt.type == '[') && !fmt.matchChar(value))
{
throw new ScanfMatchException("Input char '" + value + "' does not match '[" + fmt.cmatch + "]'");
}
consumeAndReplaceChar();
scanSuffix(fmt);
return value;
}
/**
* Scan and return a character array, whose size is determined by the field width specified in the format string (with a default width of 1 being assumed if no width is
* specified).
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion characters 'c' or '['. If
* the conversion character is '[', then each character scanned must match the sequence specified between the '[' and the closing ']' (see the documentation for
* ScanfFormat).
*
*
* White space preceding the character sequence is not skipped.
*
* @param s Format string
* @return Scanned character array
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public char[] scanChars(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanChars(new ScanfFormat(s));
}
/**
* Scan and return a character array, using the default format string "%c", with the field width (number of characters to read) supplanted by the argument n.
*
* @param n Number of characters to read
* @return Scanned character array
* @throws IllegalArgumentException n not a positive number
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanChars(String)
*/
public char[] scanChars(final int n) throws IOException, ScanfMatchException, IllegalArgumentException
{
if (n <= 0)
{
throw new IllegalArgumentException("n is non-positive");
}
return scanChars(defaultCharFmt, n);
}
/**
* Scan and return a character array, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned character array
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanChars(String)
*/
public char[] scanChars(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
return scanChars(fmt, fmt.width);
}
/**
* Scan and return a signed decimal (long) integer, using the default format string "%d".
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDec(String)
*/
public long scanDec() throws IOException, ScanfMatchException
{
long val = 0;
try
{
val = scanDec(defaultDecFmt, -1);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a signed decimal (long) integer.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 'd'. The
* integer itself must consist of an optional sign ('+' or '-') followed by a sequence of digits. White space preceding the number is skipped.
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public long scanDec(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanDec(new ScanfFormat(s));
}
/**
* Scan and return a signed decimal (long) integer, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDec(String)
*/
public long scanDec(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
return scanDec(fmt, fmt.width);
}
/**
* Scan and return a double, using the default format string "%f".
*
* @return Scanned double value
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDouble(String)
*/
public double scanDouble() throws IOException, ScanfMatchException
{
double val = 0;
try
{
val = scanDouble(defaultDoubleFmt);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a double.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 'f'. The number
* itself may consist of (a) an optional sign ('+' or '-'), (b) a sequence of decimal digits, with an optional decimal point, (c) an optional exponent ('e' or 'E'), which must
* by followed by an optionally signed sequence of decimal digits. White space immediately before the number is skipped.
*
* @param s Format string
* @return Scanned double value
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public double scanDouble(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanDouble(new ScanfFormat(s));
}
/**
* Scan and return a double, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned double value
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDouble(String)
*/
public double scanDouble(final ScanfFormat fmt) throws IOException, ScanfMatchException, IllegalArgumentException
{
// parse [-][0-9]*[.][0-9]*[eE][-][0-9]*
boolean hasDigits = false;
double value = 0;
int w;
checkTypeAndScanPrefix(fmt, "f");
if (curChar == -1)
{
throw new EOFException("EOF");
}
bcnt = 0;
w = ((fmt.width == -1) ? 1000000000 : fmt.width);
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(w);
w -= skippedSpaces;
}
if (acceptDigits(w))
{
hasDigits = true;
}
acceptChar('.', w);
if (!hasDigits && ((bcnt == w) || !Character.isDigit((char) curChar)))
{
if (curCharValid && (curChar == -1))
{
throw new EOFException("EOF");
}
throw new ScanfMatchException("Malformed floating point number: no digits");
}
acceptDigits(w);
if (acceptChar('e', w) || acceptChar('E', w))
{
if ((bcnt == w) || !Character.isDigit((char) curChar))
{
if (curCharValid && (curChar == -1))
{
throw new EOFException("EOF");
}
throw new ScanfMatchException("Malformed floating point number: no digits in exponent");
}
acceptDigits(w);
}
try
{
value = Double.parseDouble(new String(buffer, 0, bcnt));
}
catch (final NumberFormatException e)
{
throw new ScanfMatchException("Malformed floating point number");
}
scanSuffix(fmt);
return value;
}
/**
* Scan and return a float, using the default format string "%f".
*
* @return Scanned float value
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDouble(String)
*/
public float scanFloat() throws IOException, ScanfMatchException
{
return (float) scanDouble();
}
/**
* Scan and return a float. The format string s takes the same form as that described in the documentation for scanDouble(String).
*
* @param s Format string
* @return Scanned float value
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDouble(String)
*/
public float scanFloat(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return (float) scanDouble(new ScanfFormat(s));
}
/**
* Scan and return a float, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned float value
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDouble(String)
*/
public float scanFloat(final ScanfFormat fmt) throws IOException, ScanfMatchException, IllegalArgumentException
{
return (float) scanDouble(fmt);
}
/**
* Scan and return a hex (long) integer, using the default format string "%x".
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanHex(String)
*/
public long scanHex() throws IOException, ScanfMatchException
{
long val = 0;
try
{
val = scanHex(defaultHexFmt, -1);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a hex (long) integer.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 'x'. The
* integer itself must be formed from the characters [0-9a-fA-F], and white space which immediately precedes it is skipped.
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public long scanHex(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanHex(new ScanfFormat(s));
}
/**
* Scan and return a hex (long) integer, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanHex(String)
*/
public long scanHex(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
return scanHex(fmt, fmt.width);
}
/**
* Scan and return a signed integer, using the default format string "%i".
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanInt(String)
*/
public int scanInt() throws IOException, ScanfMatchException
{
return (int) scanLong();
}
/**
* Scan and return a signed integer.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain one of the conversion characters "doxi".
*
*
* Specifying the conversion characters 'd', 'o', or 'x' is equivalent to calling (int versions of) scanDec, scanOct, and scanHex, respectively.
*
*
* If the conversion character is 'i', then after an optional sign ('+' or '-'), if the number begins with an 0x, then it is scanned as a hex number; if it begins with
* an 0, then it is scanned as an octal number, and otherwise it is scanned as a decimal number. White space preceding the number is skipped.
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanDec(String)
* @see ScanfReader#scanOct(String)
* @see ScanfReader#scanHex(String)
*/
public int scanInt(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return (int) scanLong(s);
}
/**
* Scan and return a signed integer, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanInt(String)
*/
public int scanInt(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
return (int) scanLong(fmt);
}
/**
* Scan and return a signed (long) integer, using the default format string "%i".
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanInt(String)
*/
public long scanLong() throws IOException, ScanfMatchException
{
long val = 0;
try
{
val = scanLong(defaultIntFmt);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a signed (long) integer. Functionality is identical to that for scanInt(String).
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfReader#scanInt(String)
*/
public long scanLong(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanLong(new ScanfFormat(s));
}
/**
* Scan and return a signed (long) integer, using a pre-allocated ScanfFormat object.
*
* @param fmt Format object
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfReader#scanInt(String)
*/
public long scanLong(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
if (fmt.type == 'd')
{
return scanDec(fmt);
}
else if (fmt.type == 'x')
{
return scanHex(fmt);
}
else if (fmt.type == 'o')
{
return scanOct(fmt);
}
else
// fmt.type == 'i';
{
long val = 0;
int sign = 1;
int ccnt = 0;
int width = fmt.width;
if (width == -1)
{
width = 1000000000;
}
checkTypeAndScanPrefix(fmt, "i");
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(width);
width -= skippedSpaces;
}
if ((curChar == '-') || (curChar == '+'))
{
if (width == 1)
{
throw new ScanfMatchException("Malformed integer");
}
if (curChar == '-')
{
sign = -1;
}
consumeAndReplaceChar();
ccnt++;
}
if (curChar == -1)
{
throw new EOFException("EOF");
}
if (curChar == '0')
{
consumeAndReplaceChar();
ccnt++;
if (ccnt == width)
{
val = 0;
}
else
{
if ((curChar == 'x') || (curChar == 'X'))
{
if ((ccnt + 1) == width)
{
throw new ScanfMatchException("Malformed hex integer");
}
consumeAndReplaceChar();
ccnt++;
if (Character.isWhitespace((char) curChar))
{
throw new ScanfMatchException("Malformed hex integer");
}
val = scanHex(defaultHexFmt, width - ccnt);
}
else
{
if (Character.isWhitespace((char) curChar))
{
val = 0;
}
else
{
val = scanOct(defaultOctFmt, width - ccnt);
}
}
}
}
else
{ // scan unsigned decimal integer
int i = 0;
val = 0;
if (!Character.isDigit((char) curChar))
{
throw new ScanfMatchException("Malformed decimal integer");
}
while (Character.isDigit((char) curChar) && (i < (width - ccnt)))
{
val = (val * 10) + (curChar - '0');
consumeAndReplaceChar();
i++;
}
}
scanSuffix(fmt);
return sign * val;
}
}
/**
* Scan and return an octal (long) integer, using the default format string "%o".
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanOct(String)
*/
public long scanOct() throws IOException, ScanfMatchException
{
long val = 0;
try
{
val = scanOct(defaultOctFmt, -1);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return an octal (long) integer.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 'o'. The
* integer itself must be composed of the digits [0-7], and white space which immediately precedes it is skipped.
*
* @param s Format string
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public long scanOct(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanOct(new ScanfFormat(s));
}
/**
* Scan and return an octal (long) integer, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned integer
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanOct(String)
*/
public long scanOct(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
return scanOct(fmt, fmt.width);
}
/**
* Scan and return a String, using the default format string "%s".
*
* @param s Format string
* @return Scanned String
* @throws ScanfMatchException Input did not match format
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanString(String)
*/
public String scanString() throws IOException, ScanfMatchException
{
String val = null;
try
{
val = scanString(defaultStringFmt);
}
catch (final IllegalArgumentException e)
{
// can't happen
e.printStackTrace();
}
return val;
}
/**
* Scan and return a String.
*
*
* The format string s must have the form described by the documentation for the class ScanfFormat , and must contain the conversion character 's'. The string
* returned corresponds to the next non-white-space sequence of characters found in the input, with preceding white space skipped.
*
* @param s Format string
* @return Scanned String
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
*/
public String scanString(final String s) throws IOException, ScanfMatchException, IllegalArgumentException
{
return scanString(new ScanfFormat(s));
}
/**
* Scan and return a String, using a pre-allocated ScanfFormat object. This saves the overhead of parsing the format from a string.
*
* @param fmt Format object
* @return Scanned String
* @throws ScanfMatchException Input did not match format
* @throws IllegalArgumentException Error in format specification
* @throws java.io.EOFException End of file
* @throws java.io.IOException Other input error
* @see ScanfFormat
* @see ScanfReader#scanString(String)
*/
public String scanString(final ScanfFormat fmt) throws IOException, IllegalArgumentException
{
int blimit = BUFSIZE;
if ((fmt.width != -1) && (fmt.width < blimit))
{
blimit = fmt.width;
}
checkTypeAndScanPrefix(fmt, "s");
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(blimit);
blimit -= skippedSpaces;
}
if (curChar == -1)
{
throw new EOFException("EOF");
}
bcnt = 0;
while (!Character.isWhitespace((char) curChar) && (curChar != -1) && (bcnt < blimit))
{
buffer[bcnt++] = (char) curChar;
consumeAndReplaceChar();
}
scanSuffix(fmt);
return new String(buffer, 0, bcnt);
}
/**
* Sets the current character number.
*
* @param n New character number
* @see ScanfReader#getCharNumber
*/
public void setCharNumber(final int n)
{
charCnt = n;
}
/**
* Sets the current line number.
*
* @param n New line number
* @see ScanfReader#setLineNumber
*/
public void setLineNumber(final int n)
{
lineCnt = n;
}
/**
* White spaces are skipped at the beginning of a line if flag is true otherwise spaces are counted as valid characters.
*/
public boolean useCstandard()
{
return spacesCStandardFlag;
}
/**
* White spaces are skipped at the beginning of a line if flag is true otherwise spaces are counted as valid characters.
*/
public void useCstandard(final boolean flag)
{
spacesCStandardFlag = flag;
}
private final boolean acceptChar(final char c, final int width) throws IOException
{
boolean accept = false;
if ((curChar == c) && (bcnt < width))
{
buffer[bcnt++] = (char) curChar;
if (bcnt < width)
{
consumeAndReplaceChar();
}
else
{
consumeChar();
}
accept = true;
}
return accept;
}
private final boolean acceptDigits(final int width) throws IOException
{
boolean matched = false;
while (Character.isDigit((char) curChar) && (bcnt < width))
{
buffer[bcnt++] = (char) curChar;
matched = true;
if (bcnt < width)
{
consumeAndReplaceChar();
}
else
{
consumeChar();
}
}
return matched;
}
private final void checkTypeAndScanPrefix(final ScanfFormat fmt, final String type) throws IOException, IllegalArgumentException
{
if (fmt.type == -1)
{
throw new IllegalArgumentException("No conversion character");
}
if (type.indexOf(fmt.type) == -1)
{
throw new IllegalArgumentException("Illegal conversion character '" + (char) fmt.type + "'");
}
if (fmt.prefix != null)
{
matchString(fmt.prefix);
}
}
private final void consumeAndReplaceChar() throws IOException
{
if (curChar != -1)
{
charCnt++;
if ((curChar == '\r') || ((curChar == '\n') && (lastChar != '\r')))
{
lineCnt++;
}
}
lastChar = curChar;
curChar = reader.read();
}
private final void consumeChar()
{
if (curChar != -1)
{
charCnt++;
if ((curChar == '\r') || ((curChar == '\n') && (lastChar != '\r')))
{
lineCnt++;
}
}
lastChar = curChar;
curCharValid = false;
}
private final void initChar() throws IOException
{
if (!curCharValid)
{
curChar = reader.read();
curCharValid = true;
}
// charCnt = 0;
}
private void matchString(final String s) throws IOException, ScanfMatchException
{
initChar();
for (int i = 0; i < s.length(); i++)
{
final char c = s.charAt(i);
if (curChar == -1)
{
throw new EOFException("EOF");
}
if (Character.isWhitespace(c))
{
if (skipWhiteSpace() == false)
// { if (skipWhiteSpace(s.length()) == 0)
{
throw new ScanfMatchException("No white space to match white space in format");
}
}
else
{
if (curChar != c)
{
throw new ScanfMatchException("Char '" + (char) curChar + "' does not match char '" + c + "' in format");
}
consumeAndReplaceChar();
}
}
}
/**
* Implementing methodName for scanChars.
*
* @see ScanfReader#scanChars(String)
*/
private char[] scanChars(final ScanfFormat fmt, final int w) throws IOException, IllegalArgumentException
{
int wLocal = w;
if (wLocal == -1)
{
wLocal = 1;
}
final char[] value = new char[wLocal];
checkTypeAndScanPrefix(fmt, "c[");
initChar();
if (curChar == -1)
{
throw new EOFException("EOF");
}
for (int i = 0; i < wLocal; i++)
{
value[i] = (char) curChar;
if ((fmt.type == '[') && !fmt.matchChar(value[i]))
{
throw new ScanfMatchException("Input char '" + value[i] + "' does not match '[" + fmt.cmatch + "]'");
}
consumeAndReplaceChar();
}
scanSuffix(fmt);
return value;
}
/**
* Implementing methodName for scanDec.
*
* @see ScanfReader#scanDec(String)
*/
private long scanDec(final ScanfFormat fmt, final int width) throws IOException, IllegalArgumentException
{
int widthLocal = width;
if (widthLocal == -1)
{
widthLocal = 1000000000;
}
long val;
int i;
boolean negate = false;
checkTypeAndScanPrefix(fmt, "d");
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(widthLocal);
widthLocal -= skippedSpaces;
}
if ((curChar == '-') || (curChar == '+'))
{
negate = (curChar == '-');
consumeAndReplaceChar();
}
if (curChar == -1)
{
throw new EOFException("EOF");
}
if (!Character.isDigit((char) curChar))
{
throw new ScanfMatchException("Malformed decimal integer");
}
val = 0;
i = 0;
while ((Character.isDigit((char) curChar)) && (i < widthLocal))
{
val = (val * 10) + (curChar - '0');
consumeAndReplaceChar();
i++;
}
if (negate)
{
val = -val;
}
scanSuffix(fmt);
return val;
}
/**
* Implementing methodName for scanHex.
*
* @see ScanfReader#scanHex(String)
*/
private long scanHex(final ScanfFormat fmt, final int width) throws IOException, IllegalArgumentException
{
int widthLocal = width;
if (widthLocal == -1)
{
widthLocal = 1000000000;
}
long val;
int k;
int i;
checkTypeAndScanPrefix(fmt, "x");
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(widthLocal);
widthLocal -= skippedSpaces;
}
if (curChar == -1)
{
throw new EOFException("EOF");
}
if (hexChars.indexOf(curChar) == -1)
{
throw new ScanfMatchException("Malformed hex integer");
}
val = 0;
i = 0;
while (((k = hexChars.indexOf(curChar)) != -1) && (i < widthLocal))
{
if (k > 15)
{
k -= 6;
}
val = (val * 16) + k;
consumeAndReplaceChar();
i++;
}
scanSuffix(fmt);
return val;
}
/**
* Implementing methodName for scanOct.
*
* @see ScanfReader#scanOct(String)
*/
private long scanOct(final ScanfFormat fmt, final int width) throws IOException, IllegalArgumentException
{
int widthLocal = width;
if (widthLocal == -1)
{
widthLocal = 1000000000;
}
long val;
int k;
int i;
checkTypeAndScanPrefix(fmt, "o");
if (spacesCStandardFlag)
{
skipWhiteSpace();
}
else
{
final int skippedSpaces = skipWhiteSpace(widthLocal);
widthLocal -= skippedSpaces;
}
if (curChar == -1)
{
throw new EOFException("EOF");
}
if (octChars.indexOf(curChar) == -1)
{
throw new ScanfMatchException("Malformed octal integer");
}
val = 0;
i = 0;
while (((k = octChars.indexOf(curChar)) != -1) && (i < widthLocal))
{
val = (val * 8) + k;
consumeAndReplaceChar();
i++;
}
scanSuffix(fmt);
return val;
}
// private final void scanPrefix(ScanfFormat fmt) throws IOException
// {
// if (fmt.prefix != null)
// {
// matchString(fmt.prefix);
// }
// }
private final void scanSuffix(final ScanfFormat fmt) throws IOException
{
if (fmt.suffix != null)
{
matchString(fmt.suffix);
}
}
/**
* Skip white spacew and count line numbers.
*/
private boolean skipWhiteSpace() throws IOException
{
boolean encounterdWhiteSpace = false;
initChar();
while (Character.isWhitespace((char) curChar))
{
encounterdWhiteSpace = true;
consumeAndReplaceChar();
}
return encounterdWhiteSpace ? true : false;
}
/**
* Skip white spacew and count line numbers.
*
* @param limit the maximum of the number that will be skipped
* @return the number of skipped white spaces
*/
private int skipWhiteSpace(final int limit) throws IOException
{
initChar();
int spaces = 0;
while (Character.isWhitespace((char) curChar) && (spaces <= limit))
{
spaces++;
consumeAndReplaceChar();
}
return spaces;
}
}
// /////////////////////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
// END OF FILE.
// /////////////////////////////////////////////////////////////////////////////