//============================================================================== // 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