/* **************************************************************************
 %name: %
 %version: %
 %date_modified: %

 Copyright (c) 1997,1998 Novell, Inc. All Rights Reserved.

 THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND TREATIES.
 USE AND REDISTRIBUTION OF THIS WORK IS SUBJECT TO THE LICENSE AGREEMENT
 ACCOMPANYING THE SOFTWARE DEVELOPMENT KIT (SDK) THAT CONTAINS THIS WORK.
 PURSUANT TO THE SDK LICENSE AGREEMENT, NOVELL HEREBY GRANTS TO DEVELOPER A
 ROYALTY-FREE, NON-EXCLUSIVE LICENSE TO INCLUDE NOVELL'S SAMPLE CODE IN ITS
 PRODUCT. NOVELL GRANTS DEVELOPER WORLDWIDE DISTRIBUTION RIGHTS TO MARKET,
 DISTRIBUTE, OR SELL NOVELL'S SAMPLE CODE AS A COMPONENT OF DEVELOPER'S
 PRODUCTS. NOVELL SHALL HAVE NO OBLIGATIONS TO DEVELOPER OR DEVELOPER'S
 CUSTOMERS WITH RESPECT TO THIS CODE.
****************************************************************************/

import java.io.*;

/**
 * Supports reading text input lines from an arbitrary input stream
 * or reader. It uses the System property 'line.separator' to separate
 * the lines.
 */
public class LineReader
{
   InputStream is = null;
   Reader ir = null;
   char[] lineTerminator = System.getProperty ("line.separator").
         toCharArray ();

   /**
    * Constructs a line reader using an input stream as the input
    * source.
    *
    * @param is The InputStream to be read.
    */
   public LineReader (InputStream is)
   {
      this.is = is;
   }

   /**
    * Constructs a line reader using a reader as the input source.
    *
    * param ir The reader to be used as the input source.
    */
   public LineReader (Reader ir)
   {
      this.ir = ir;
   }

   /**
    * Reads one character from the input source.
    */
   private int read ()
   throws IOException
   {
      if (is != null)
         return (is.read ());
      else if (ir != null)
         return (ir.read ());
      else
         throw new IllegalStateException ();
   }

   /**
    * Reads and returns all characters up to but not including the
    * complete line termination sequence.
    *
    * @return  The characters read as a string. If the stream contains
    *          no more characters, this method returns null.
    *
    * @exception IOException When an error occurs reading characters.
    */
   public String readLine ()
   throws IOException
   {
      StringBuffer buf = new StringBuffer ();
      char[] save = new char[lineTerminator.length];
      int pos = 0;
      int ch = read ();
      boolean done = false;

      // if EOF (no more characters to read)
      if (ch < 0)
         return (null);

      do
      {
         if (ch == lineTerminator[pos])
         {
            save[pos] = (char) ch;
            pos++;
         }
         else
         {
            /* If a char in the line terminator is returned
             * but one was skipped, then skip it by moving pos
             * up by two.
             */
            if (pos + 1 < lineTerminator.length &&
                ch == lineTerminator[pos + 1])
               pos += 2;
            else
            {
               /* If we've matched one or more characters already in
                * the line termination sequence, but the matching has
                * stopped, then we append all previously matched chars
                * onto our line buffer.
                */
               if (pos > 0)
               {
                  buf.append (save, 0, pos);
                  pos = 0;
               }

               buf.append ((char) ch);
            }
         }

         done = pos >= lineTerminator.length;

         if (!done)
            ch = read ();

         // if EOF, we are automatically done
         if (ch < 0)
            done = true;
      } while (!done);

      return (new String (buf));
   }
}