//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\ //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ using System; using System.IO; using System.Text; using Ilog.Language.Util; using Ilog.Language.Tools; namespace Ilog.Language.IO { /** * This class implements a Reader that may include another Reader * in midstream reading, and eventually resume reading at that point * upon reaching EOF in the included Reader. * *
* * By default, included readers are read seamlessly. That is, when starting or * ending an inclusion, the next character is that which starts the included * reader or the next one in the enclosing reader. Inclusion seams may or not be * made visible with setSeamless(bool). Called with false on * an IncludeReader object, it will make its read() return * CC.SOI ('start of inclusion') or CC.EOI ('end of inclusion'), * both int constants, when starting or ending, respectively, reading an * inclusion. Calling it with true re/sets seamless reading. * *
*
* NB: It is possible to prevent circular inclusions, although
* not in all situations. Indeed there is no way, in general, for an
* arbitary Reader to be identified as reading from a source being
* actively included. However, this can be done for IncludeReaders
* constructed from file readers by using the IncludeReader(string)
* constructor and the include(string) method, which provide
* identifiable file names. For file readers included using this
* constructor and method, any circular inclusion will be detected
* and cause a CircularInclusionException to be thrown.
*
* @see CircularInclusionException
*
* @version Last modified on Sun May 29 13:27:04 2005 by hak
* @author Hassan Aït-Kaci
* @copyright © 2002 ILOG, S.A.
*/
public class IncludeReader : TextReader
{
/**
* The current underlying reader.
*/
private TextReader _reader;
/**
* The name of the file associated to the current reader - or null
* if the current reader is not reading from a file.
*/
private string _file;
/**
* The current line number of the current reader.
*/
private int _line = 1;
/**
* The current column number on the current line of the current reader.
*/
private int _col = 0;
/**
* The stack recording the suspended readers.
*/
private Stack _readerStack = new Stack();
/**
* The set of files currently being actively included.
*/
private HashSet _dejaVu = new HashSet();
/**
* A flag indicating whether inclusions are seamless.
*/
private bool _isSeamless = true;
/**
* A flag indicating that nothing has been read yet from the
* current reader.
*/
private bool _isInclusionStart = false;
/**
* The latest character read in the current reader.
*/
private int _chr = CC.SOI;
// HAK 2 HAK: the constructors should throw an exception if used with a
// reader of type Ilog.Language.Io.LAReader!!!
/**
* Constructs an IncludeReader with the specified Reader.
*/
public IncludeReader (TextReader reader)
{
_reader = reader;
}
/**
* Constructs an IncludeReader with the specified file name.
*
* @throws FileNotFoundException (f the specified file does not exist)
*/
public IncludeReader (string file) // throws FileNotFoundException
{
_reader = new StreamReader(file);
_file = file;
_dejaVu[file] = true;
}
/**
* Sets or unsets seamless inclusion mode.
*/
public void SetSeamless (bool flag)
{
_isSeamless = flag;
}
/**
* Returns true iff this IncludeReader is seamless.
*/
public bool IsSeamless ()
{
return _isSeamless;
}
/**
* This is the name of the file associated to the current reader -
* or null if the current reader is not reading from a file.
*/
public string FileName
{
get
{
if (_file == null && _reader is IncludeReader)
return ((IncludeReader)_reader).FileName;
return _file;
}
set
{
_file = value;
}
}
/**
* This is latest character read in the current reader.
*/
public int LatestChar
{
get { return _chr; }
}
/**
* This is the current line number of the current reader.
*/
public int LineNumber
{
get { return _line; }
}
/**
* This is the current column number of the current reader.
*/
public int ColumnNumber
{
get { return _col; }
}
/**
* Closes all readers associated with this IncludeReader.
*
* @throws IOException (if an I/O error occurs)
*/
public override void Close () // Throws IOException
{
while (!(_readerStack.Count == 0))
((ReaderStackElement)_readerStack.Pop()).Reader().Close();
_reader.Close();
}
/**
* Returns the depth of inclusion of the current reader.
*/
public int Depth ()
{
return _readerStack.Count;
}
/**
* Returns true iff this is reading from the outermost reader.
*/
public bool IsOutermost ()
{
return _readerStack.Count == 0;
}
/**
* Reads and returns the next character in this IncludeReader. When
* not in seamless mode, returns CC.SOI (resp., CC.EOI) right
* before starting (resp., after ending) reading an inclusion. Returns
* CC.EOF only at the end of the outermost enclosing reader.
*
* @return The character read (0 to 65535), CC.EOF, CC.EOI, or CC.SOI.
* @throws IOException (if an I/O error occurs)
*/
public override int Read () // throws IOException
{
if (_isInclusionStart)
{
_isInclusionStart = false;
_chr = CC.SOI;
}
else
{
_chr = _reader.Read();
while (_chr == CC.EOF)
{
if (_readerStack.Count == 0)
break;
_reader.Close();
if (_file != null)
_dejaVu[_file] = false;
ReaderStackElement elt = (ReaderStackElement)_readerStack.Pop();
_reader = elt.Reader();
_file = elt.File();
_line = elt.Line();
_col = elt.Col();
_chr = CC.EOI;
}
}
switch (_chr)
{
case CC.SOI:
_line = 1;
_col = 0;
break;
case CC.EOI: case CC.EOF:
break;
case CC.EOL:
_line++;
_col = 0;
break;
case CC.BSP:
if (_col > 0)
_col--;
break;
default:
_col++;
break;
}
if (_isSeamless && (_chr == CC.SOI || _chr == CC.EOI))
return Read();
eof = (_chr == CC.EOF);
return _chr;
}
/**
* Returns the next character in this IncludeReader without
* removing it as next to be read. When not in seamless mode, this will
* return CC.SOI (resp., CC.EOI) if they are next
* to be read. Returns CC.EOF only if the character that would
* be returned by an actual read is the end of the outermost enclosing
* reader.
*
* @return The character read (0 to 65535), CC.EOF, CC.EOI, or CC.SOI.
* @throws IOException (if an I/O error occurs)
*/
public override int Peek () // throws IOException
{
if (_isInclusionStart && !_isSeamless)
return CC.SOI;
int next = _reader.Peek();
if (next == CC.EOF)
{
if (_readerStack.Count == 0)
return CC.EOF;
foreach (Object elt in _readerStack)
{
next = ((ReaderStackElement)elt).Reader().Peek();
if (next != CC.EOF)
break;
}
if (next != CC.EOF && !_isSeamless)
return CC.EOI;
}
return next;
}
/**
* Suspends reading from the current reader and makes further reads
* proceed with the specified reader. Reading from the suspended reader
* at the exact point it was left resumes automatically upon reaching
* the end of the included reader.
*
*/
public void Include (TextReader reader)
{
_readerStack.Push(new ReaderStackElement(_reader,_line,_col));
_reader = reader;
_isInclusionStart = true;
}
/**
* Suspends reading from the current reader and makes further reads
* proceed with a reader from the specified file. Reading from the
* suspended file reader at the exact point it was left resumes
* automatically upon reaching the end of the included file.
*
* @throws FileNotFoundException (if the specified file does not exist)
* @throws CircularInclusionException (if trying to open an enclosing Reader)
*/
public void Include (string file) // throws FileNotFoundException, CircularInclusionException
{
if (_dejaVu[file])
throw new CircularInclusionException(file);
_readerStack.Push(new ReaderStackElement(_reader,_file,_line,_col));
_reader = new StreamReader(file);
_file = file;
_dejaVu[file] = true;
_isInclusionStart = true;
}
/**
* Read characters into a portion of an array. Note that if not in seamless mode,
* CC.EOI and CC.SOI will be read into the array like any other character.
*
* @param cbuf Destination buffer
* @param off Offset at which to start storing characters
* @param len Maximum number of characters to read
* @return number of characters read or CC.EOF
* @throws IOException (if an I/O error occurs)
*/
public override int ReadBlock (char[] cbuf, int off, int len) // throws IOException
{
return Read(cbuf,off,len);
}
/**
* Read characters into a portion of an array. Note that if not in seamless mode,
* CC.EOI and CC.SOI will be read into the array like any other character.
*
* @param cbuf Destination buffer
* @param off Offset at which to start storing characters
* @param len Maximum number of characters to read
* @return number of characters read or CC.EOF
* @throws IOException (if an I/O error occurs)
*/
public override int Read (char[] cbuf, int off, int len) // throws IOException
{
int c;
int count = 0;
while (off < cbuf.Length && count < len)
switch (c = Read())
{
case CC.EOF:
return c;
default:
cbuf[off] = (char)c;
off++;
count++;
break;
}
return count;
}
/**
* Read characters into an array.
*
* @param cbuf Destination buffer
* @return Number of characters read, or one of CC.EOF, CC.SOI, or CC.EOI.
* @throws IOException (if an I/O error occurs)
*/
public int Read (char[] cbuf) // throws IOException
{
return Read(cbuf,0,cbuf.Length);
}
/**
* Skip n characters or until CC.EOF is found. Note that
* CC.SOI and CC.EOI are skipped but not counted, regardless of
* whether the inclusion mode is seamless or not.
*
* @param n The number of characters to skip
* @return The number of characters actually skipped
* @throws IllegalArgumentException (if n is negative)
* @throws IOException (if an I/O error occurs)
*/
public long Skip (long n) // throws IOException
{
if (n < 0)
throw new ArgumentException
("Cannot skip negative number of chars: "+n);
int count = 0;
while (count < n)
switch (Read())
{
case CC.EOF:
return count;
case CC.EOI: case CC.SOI:
continue;
default:
count++;
break;
}
return count;
}
/**
* This is true iff the end of the outermost reader has been reached.
*/
private bool eof = false;
/**
* Reads up to the end of line or the end of current reader,
* whichever comes first, and returns the line as a string.
* Returns null if end of file has been reached.
*/
public override string ReadLine ()
{
if (eof)
return null;
StringBuilder buf = new StringBuilder();
for (int chr = Read(); (chr != CC.EOL && chr != CC.EOF); chr = Read())
buf.Append((char)chr);
return buf.ToString();
}
/**
* If in seamless mode, reads from the current buffer's position up
* to the end of the outermost reader and returns the result as a
* string. Otherwise, reads up to the end of the current reader and
* returns the result as a string. All exhausted readers are closed
* after this is called.
*/
public override string ReadToEnd ()
{
StringBuilder buf = new StringBuilder(_reader.ReadToEnd());
_reader.Close();
if (_isSeamless)
while (_readerStack.Count != 0)
{
_reader = ((ReaderStackElement)_readerStack.Pop()).Reader();
buf.Append(_reader.ReadToEnd());
_reader.Close();
}
return buf.ToString();
}
/**
* Returns a string form describing the current state of the reader.
*/
public override string ToString ()
{
return "