//============================================================================== // tribble/io/LineReader.java //------------------------------------------------------------------------------ package tribble.io; // System imports import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.LineNumberReader; import java.io.Reader; import java.lang.Exception; import java.lang.String; import java.lang.System; // Local imports // (None) /******************************************************************************* * Text line reader. * Reads text lines from a text file. * *
* This class extends the standard java.io.LineNumberReader class,
* performing the same functions, except that it expands tabs (HT,
* '\u0009') characters into spaces.
* By default, tabs are assumed to be aligned on 8-space columns, but this can be
* changed by calling the {@link #setTabWidth} method.
*
* @version $Revision: 1.5 $ $Date: 2003/02/16 22:45:37 $
* @since 2002-12-21
* @author
* David R. Tribble,
* david@tribble.com.
*
* Copyright
* ©2002-2003 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source code
* provided that the original copyright and authorship notices remain
* intact.
*
* @see java.io.LineNumberReader
*/
public class LineReader
extends java.io.LineNumberReader
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/io/LineReader.java $Revision: 1.5 $ $Date: 2003/02/16 22:45:37 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public constants
/** Default tab width. */
public static int DFL_TABSIZE = 8;
/** Default maximum input text line buffer size. */
public static int DFL_BUFSIZE = 2000;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Static methods
/***************************************************************************
* Test driver.
* Reads text lines from one or more text files.
*
*
* Usage *
* java tribble.io.LineReader file...
*
* @param args
* Command line arguments.
*
* @since 1.2, 2002-12-23
*/
public static void main(String[] args)
{
// Check args
if (args.length < 1)
{
System.out.println("usage: java " + LineReader.class.getClass()
+ " file...");
System.out.println();
System.out.println("A filename of '-' specifies the standard input"
+ " stream");
System.exit(255);
}
// Read one or more text files
for (int i = 0; i < args.length; i++)
{
String inFilename;
// Open a named input file
inFilename = args[i];
try
{
LineNumberReader in;
// Open the named input file
if (inFilename.equals("-"))
in = new LineReader(new InputStreamReader(System.in));
else
in = new LineReader(new FileReader(inFilename));
// Read and print the input file contents
if (i > 0)
System.out.println();
System.out.println(inFilename + ":");
for (;;)
{
String ln;
int n;
// Read a line of text from the input file
ln = in.readLine();
if (ln == null)
break;
// Get the line number of the text line just read
n = in.getLineNumber();
System.out.print(
(n < 100 ? " " : "") + (n < 10 ? " " : "") + n
+ ": [");
// Display the text line
while (ln != null)
{
String text;
text = ln;
if (ln.length() >= 50)
text = ln.substring(0, 50);
System.out.print(text);
if (ln.length() > 50)
ln = ln.substring(50);
else
ln = null;
}
System.out.println("]");
}
// Clean up
if (!inFilename.equals("-"))
in.close();
}
catch (FileNotFoundException ex)
{
// Cannot open/read a named file
System.out.println("Can't open/read '" + inFilename + "', "
+ ex.getMessage());
}
catch (IOException ex)
{
// I/O (read) error
System.out.println("IOException: " + ex.getMessage());
}
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Protected variables
/** Underlying input reader. */
protected Reader m_in;
/** Tab width, zero specifies no tab expansion. */
protected int m_tabSize = DFL_TABSIZE;
/** Column number of the last character read (starting at 1). */
protected int m_colNo;
/** Pending spaces remaining for a tab expansion. */
protected int m_spacesLeft;
/** Input text line buffer. */
protected char[] m_buf;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public contructors
/***************************************************************************
* Constructor.
*
* @param in
* A character input stream to read characters from.
* This cannot be null.
*
* @since 1.1, 2002-12-21
*/
public LineReader(Reader in)
{
// Establish the character input stream
this(in, DFL_BUFSIZE);
m_in = in;
}
/***************************************************************************
* Constructor.
*
* @param in
* A character input stream to read characters from.
* This cannot be null.
*
* @param bufSize
* The size of the input buffer to use for this input stream.
*
* @since 1.3, 2002-12-23
*/
public LineReader(Reader in, int bufSize)
{
// Establish the character input stream
super(in);
m_in = in;
m_buf = new char[bufSize];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Public methods
/***************************************************************************
* Establish the number of spaces that tab characters are expanded into.
*
* * By default, tabs are expanded into spaces so as to align on every * {@link #DFL_TABSIZE} column. * * @param n * The number of columns that tab characters align to. * This can be zero, which specifies that tabs are not be replaced with * spaces, but should be left as is. * * @since 1.2, 2002-12-22 * * @see #getTabWidth */ public void setTabWidth(int n) { // Establish the tab width m_tabSize = n; } /*************************************************************************** * Retrieve the number of spaces that tab characters are expanded into. * * @return * The number of columns that tab characters align to. * This can be zero, which specifies that tabs are not be replaced with * spaces, but should be left as is. * * @since 1.2, 2002-12-22 * * @see #setTabWidth */ public int getTabWidth() { // Retrieve the tab width return (m_tabSize); } /*************************************************************************** * Read a single line of text from this input stream. * *
* This method operates the same as {@link java.io.LineNumberReader#readLine} * except that it expands tab characters into spaces. The number of spaces * is specified by a prior call to method {@link #setTabWidth}. * *
* Input lines are terminated by either a linefeed ('\u000A'), a * carriage return ('\u000D'), or a carriage return followed by a * linefeed ('\u000D\u000A'). Input lines are also considered * terminated if they are followed by an end-of-file marker. * *
* Invalid characters (i.e., nonprinting control characters) are replaced by * spaces. * * @return * A string containing the text of the next input line, or null if the end of * the input stream was reached. * This string can be empty (""), indicating that the input line was * composed of only a newline. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.1, 2002-12-21 * * @see #setTabWidth */ public String readLine() throws IOException //overrides java.io.LineNumberReader { synchronized (lock) { String ln; int i; // Read the next input line i = 0; for (i = 0; i < m_buf.length; i++) { int ch; // Read the next input character ch = readChar(); // Check for end of file (EOF) if (ch == -1) { if (i == 0) return (null); // Treat EOF as end of line break; } // Check for end of line if (ch == '\n') break; // Append the character to the line buffer m_buf[i] = (char) ch; } // Build a string out of the input line buffer ln = new String(m_buf, 0, i); return (ln); } } /*************************************************************************** * Read characters into a portion of an array. * * @param buf * A character array to read characters into. * * @param off * Index of the first character within buf to read. * * @param len * The maximum number of characters to read into buf. * * @return * The actual number of characters read into array buf, which may be * less than len. * * @since 1.2, 2002-12-21 */ public int read(char[] buf, int off, int len) throws IOException //overrides java.io.LineNumberReader { synchronized (lock) { int i; // Read characters into 'buf' for (i = 0; i < len; i++) { int ch; ch = readChar(); if (ch == -1) break; buf[i+off] = (char) ch; if (ch == '\n') break; } // Return the number of characters read into 'buf' return (i); } } /*************************************************************************** * Determine whether the {@link #mark} method is supported or not. * * @return * A value specifying whether the underlying input reader supports the * mark() method or not. * * @since 1.2, 2002-12-22 * * @see #mark */ public boolean markSupported() //overrides java.io.LineNumberReader { // Determine if the underlying reader supports the operation return (m_in.markSupported()); } /*************************************************************************** * Mark the present position in this input stream. * * @param limit * Limit on the number of characters that may be read while still preserving * the mark. * * @throws IOException * Thrown if this operation is not supported, or if some other I/O error * occurs. * * @since 1.2, 2002-12-22 * * @see #markSupported * @see #reset */ public void mark(int limit) throws IOException //overrides java.io.LineNumberReader { // Mark the underlying reader m_in.mark(limit); } /*************************************************************************** * Reset this input stream to the most recent mark. * * @throws IOException * Thrown if this operation is not supported, or if some other I/O error * occurs. * * @since 1.2, 2002-12-22 * * @see #mark */ public void reset() throws IOException //overrides java.io.LineNumberReader { // Reset the underlying reader m_in.reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Protected methods /*************************************************************************** * Read a single text character from this input stream. * *
* This method operates the same as {@link java.io.LineNumberReader#readLine} * except that it expands tab characters into spaces. The number of spaces * is specified by a prior call to method {@link #setTabWidth}. * *
* Invalid characters (i.e., nonprinting control characters) are replaced by * spaces. * *
* Note *
* This method is not synchronized, so any public member methods calling this * method should be synchronized themselves. * * @return * A character code, or -1 if the end of the input stream has been reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.2, 2002-12-22 * * @see #read * @see #readLine */ protected int readChar() throws IOException //overrides java.io.LineNumberReader { int ch; // Check for an unfinished tab character expansion if (m_spacesLeft > 0) { m_spacesLeft--; m_colNo++; return (' '); } // Read the next input char // Note that this call adjusts for newlines (LF, CR, CR/LF) ch = super.read(); // Check for end of input if (ch == -1) return (-1); // Check for special characters if (ch == '\t') { if (m_tabSize > 0) { // Replace a tab character with spaces m_spacesLeft = m_tabSize-1 - m_colNo%m_tabSize; ch = ' '; } // Else leave the tab (HT) character as is } else if (ch == '\n') { // Newline (LF) character, leave it as is m_colNo = -1; } else if (ch < 0x0020 || (ch >= 0x0080 && ch < 0x00A0)) { // Nonprinting (control) character, replace it with a space (SP) ch = ' '; } // Done m_colNo++; return (ch); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Private contructors /*************************************************************************** * Default constructor. * This is private to prevent empty instantiations. * * @since 1.1, 2002-12-21 */ private LineReader() { // Do nothing super(null); } } // End LineReader.java