using System;
using System.IO;
using System.Text;
/** Simple input from the keyboard or from a file.
This class allows reading formatted data either from the keyboard,
from a file or from a string. It is intended to be used in an introductory
programming course when classes, packages and exceptions are unknown
at the beginning.
All input comes from the current input stream, which is initially
the keyboard. Opening a file with Open() or a string with OpenString()
makes it the new current input stream. Closing a stream with Close()
switches back to the previous input stream.
When reading from the keyboard, the reading blocks until the user has entered
a sequence of characters terminated by the return key. All methods read
from this input buffer (including the terminating '\r' and '\n') until the
buffer is fully consumed. When a method tries to read beyond the end
of the buffer, it blocks again waiting for the next buffer.
End of file detection: When reading from the keyboard, eof can be
signaled as ctrl-E followed by the return key. When reading from a file or string,
eof occurs when an attempt is made to read beyond the end of the stream.
In either case In.Done returns false if the requested data could not
be read because of eof.
*/
public class In {
/// End of file indicator returned by read() or peek() when no more
/// characters can be read.
public const char eof = '\uffff';
const char empty = '\ufffe';
const char CR = '\r';
const char eofChar = '\u0005'; // ctrl E
static TextReader input;
static TextReader[] stack;
static int sp; // stack pointer
static bool done; // true if recent operation was successful
static char buf; // last read character
static char CharAfterWhiteSpace() {
char c;
do c = Read(); while (done && c <= ' ');
return c;
}
static string ReadDigits() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
if (done && c == '-') {
b.Append(c);
c = Read();
}
while (done && Char.IsDigit(c)) {
b.Append(c);
c = Read();
}
buf = c;
return b.ToString();
}
static string ReadFloatDigits() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
while (done && (Char.IsDigit(c) || c == '.' || c == '+' || c == '-'
|| c == 'e' || c == 'E')) {
b.Append(c);
c = Read();
}
buf = c;
return b.ToString();
}
/// Read a character (byte).
/// If an attempt is made to read beyond the end of the file,
/// eof is returned and Done yields false. Otherwise the read byte
/// is in the range 0..255.
public static char Read() {
char c;
if (buf != empty) {
c = buf;
if (buf != eof) buf = empty;
} else {
try {
c = (char)input.Read();
} catch (IOException) {
done = false;
c = eof; buf = eof;
}
}
if (sp == 0 && c == eofChar) { c = eof; buf = eof; }
done = c != eof;
return c;
}
/// Read a boolean value.
/// This method skips white space and tries to read an identifier. If its value
/// is "true" the method returns true otherwise false. If the identifier is neither
/// "true" nor "false" Done yields false.
public static bool ReadBool() {
string s = ReadIdentifier();
done = true;
if (s == "true") return true;
else { done = s == "false"; return false; }
}
/// Read an identifier.
/// This method skips white space and tries to read an identifier starting
/// with a letter and continuing with letters or digits. If a token of this
/// structure could be read, it is returned otherwise the empty string is
/// returned and Done yields false.
public static string ReadIdentifier() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
if (done && Char.IsLetter(c)) {
b.Append(c);
c = Read();
while (done && (Char.IsLetter(c) || Char.IsDigit(c))) {
b.Append(c);
c = Read();
}
}
buf = c;
done = b.Length > 0;
return b.ToString();
}
/// Read a word.
/// This method skips white space and tries to read a word consisting of
/// all characters up to the next white space or to the end of the file.
/// If a token of this structure could be read, it is returned otherwise
/// an empty string is returned and Done yields false.
public static string ReadWord() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
while (done && c > ' ') {
b.Append(c);
c = Read();
}
buf = c;
done = b.Length > 0;
return b.ToString();
}
/// Read a line of text.
/// This method reads the rest of the current line (including CR+LF) and
/// returns it (excluding CR+LF). A line may be empty.
public static string ReadLine() {
StringBuilder b = new StringBuilder();
char c = Read();
while (done && c != CR) {
b.Append(c);
c = Read();
}
if (c == CR) c = Read(); // read also LF
buf = empty;
if (b.Length > 0) done = true;
return b.ToString();
}
/// Read the whole file.
/// This method reads from the current position to the end of the
/// file and returns its text in a single large string. Done yields
/// always true.
public static string ReadFile() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
while (done) {
b.Append(c);
c = Read();
}
buf = eof;
done = true;
return b.ToString();
}
/// Read a quote-delimited string.
/// This method skips white space and tries to read a string in the form "...".
/// It returns the string without enclosing quotes.
/// This method can be used to read pieces of text that contain white space.
public static string ReadString() {
StringBuilder b = new StringBuilder();
char c = CharAfterWhiteSpace();
if (done && c == '"') {
c = Read();
while (done && c != '"') {
b.Append(c);
c = Read();
}
if (c == '"') { c = Read(); done = true; } else done = false;
} else done = false;
buf = c;
return b.ToString();
}
/// Read an integer.
/// This method skips white space and tries to read an integer. If the
/// text does not contain an integer or if the number is too big, the
/// value 0 is returned and the subsequent access to Done yields false.
/// An integer is a sequence of digits, possibly preceded by '-'.
public static int ReadInt() {
string s = ReadDigits();
try {
done = true;
return Convert.ToInt32(s);
} catch (Exception) {
done = false; return 0;
}
}
/// Read a long integer.
/// This method skips white space and tries to read a long integer. If the
/// text does not contain a number or if the number is too big, the
/// value 0 is returned and the subsequent access to Done yields false.
/// A long integer is a sequence of digits, possibly preceded by '-'.
public static long ReadLong() {
string s = ReadDigits();
try {
done = true;
return Convert.ToInt64(s);
} catch (Exception) {
done = false; return 0;
}
}
/// Read a float value.
/// This method skips white space and tries to read a float value. If the
/// text does not contain a float value or if the number is not well-formed,
/// the value 0f is returned and the subsequent access to Done yields false.
/// A float value is as specified in the C# language description. It may
/// be preceded by a '+' or a '-'.
public static float ReadFloat() {
string s = ReadFloatDigits();
try {
done = true;
return Convert.ToSingle(s);
} catch (Exception) {
done = false; return 0f;
}
}
/// Read a double value.
/// This method skips white space and tries to read a double value. If the
/// text does not contain a double value or if the number is not well-formed,
/// the value 0.0 is returned and the subsequent access to Done yields false.
/// A double value is as specified in the C# language description. It may
/// be preceded by a '+' or a '-'.
public static double ReadDouble() {
String s = ReadFloatDigits();
try {
done = true;
return Convert.ToDouble(s);
} catch (Exception) {
done = false; return 0.0;
}
}
/// Peek at the next character.
/// This method skips white space and returns the next character without removing
/// it from the input stream. It can be used to find out, what token comes next
/// in the input stream.
public static char Peek() {
buf = CharAfterWhiteSpace();
return buf;
}
/// Open a text file for reading
/// The text file with the name fn is opened as the new current input
/// file. When it is closed again, the previous input file is restored.
public static void Open(string fn) {
try {
FileStream s = new FileStream(fn, FileMode.Open);
StreamReader r = new StreamReader(s);
stack[sp++] = input;
input = r;
done = true;
} catch (FileNotFoundException) {
done = false;
}
buf = empty;
}
/// Open a string for reading
/// The string s is opened as the new current input stream.
/// When it is closed again, the previous input stream is restored.
public static void OpenString(string s) {
try {
StringReader r = new StringReader(s);
stack[sp++] = input;
input = r;
done = true;
} catch (ArgumentNullException) {
done = false;
}
buf = empty;
}
/// Close the current input file.
/// The current input file is closed and the previous input file is
/// restored. Closing the keyboard input has no effect but causes
/// Done to yield false.
public static void Close() {
try {
if (sp > 0) {
input.Close();
input = stack[--sp];
done = true;
} else {
done = false;
}
} catch (IOException) {
done = false;
}
buf = empty;
}
/// Check if the previous operation was successful.
/// This property returns true if the previous read operation was able
/// to read a token of the requested structure. It can also be queried
/// after Open() and Close() to check if these operations were successful.
/// If Done is accessed before any other operation it yields true.
public static bool Done {
get {return done;}
}
static In() { // initializer
done = true;
input = Console.In;
stack = new TextReader[8];
sp = 0;
buf = empty;
}
}