[32m--- ../lib/csv.rb[0m
  # CSV -- module for generating/parsing CSV data.
    
  # $Id: coverage.txt,v 1.4 2002/11/09 13:03:21 nahi Exp $
    
  # This module is copyrighted free software by NAKAMURA, Hiroshi.
  # You can redistribute it and/or modify it under the same term as Ruby.
    
    
[31m+ class CSV[0m
[31m+ public[0m
  
    # DESCRIPTION
    #   CSV::Cell -- Describes 1 cell of CSV.
    #   
[31m+   class Cell[0m
[31m+   public[0m
    
      # Datum as string.
[31m+     attr_accessor :data[0m
      
      # Is this datum null?
[31m+     attr_accessor :isNull[0m
  
      # SYNOPSIS
      #   aCell = CSV::Cell.new( data = "", isNull = true )
      #
      # ARGS
      #   data: datum as String
[31m+     #   isNull: is this datum null?[0m
      #
      # RETURNS
      #   aCell: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  If isNull is true, datum is stored in the instance
      #   created but it should be treated as "NULL".
      #   
[31m+     def initialize( data = "", isNull = true )[0m
[31m+       @data = data[0m
[31m+       @isNull = isNull[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Cell#match( rhs )
      #
      # ARGS
      #   rhs: an instance of CSV::Cell to be compared.
      #
      # RETURNS
      #   true/false.  See the souce if you want to know matching algorithm.
      #
      # DESCRIPTION
      #   Compare another cell with me.  Bare in mind Null matches with Null
      #   using this method.  Use CSV::Cell#== if you want Null never matches
      #   with other data including Null.
      #
[31m+     def match( rhs )[0m
[31m+       if @isNull and rhs.isNull[0m
[31m+ 	return true[0m
[31m+       elsif @isNull or rhs.isNull[0m
[31m+ 	return false[0m
[31m+       end[0m
[31m+       @data == rhs.data[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Cell#==( rhs )
      #
      # ARGS
      #   rhs: an instance of CSV::Cell to be compared.
      #
      # RETURNS
      #   true/false.  See the souce if you want to know matching algorithm.
      #
      # DESCRIPTION
      #   Compare another cell with me.  Bare in mind Null is not match with
      #   Null using this method.  Null never matches with other data including
      #   Null.  Use CSV::Cell#match if you want Null matches with Null.
      #
[31m+     def ==( rhs )[0m
[31m+       if @isNull or rhs.isNull[0m
[31m+ 	return false[0m
[31m+       end[0m
[31m+       @data == rhs.data[0m
[31m+     end[0m
[31m+   end[0m
    
    # For backward compatibility.
[31m+   ColData = Cell[0m
  
  
    # DESCRIPTION
    #   CSV::Row -- Describes a row of CSV.  Each element must be a CSV::Cell.
    #   
[31m+   class Row < Array[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   CSV::Row#to_a
      #
      # RETURNS
      #   An Array of String.
      #
      # DESCRIPTION
      #   Convert CSV::Cell to String.  Null is converted to nil.
      #
[31m+     def to_a[0m
[31m+       self.collect { | cell | cell.isNull ? nil : cell.data }[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Row#match( rhs )
      #
      # ARGS
      #   rhs: an Array of cells.  Each cell is a instance of CSV::Cell.
      #
      # RETURNS
      #   true/false.  See the souce if you want to know matching algorithm.
      #
      # DESCRIPTION
      #   Compare another row with me.
      #
[31m+     def match( rhs )[0m
[31m+       if self.size != rhs.size[0m
[31m+ 	return false[0m
[31m+       end[0m
[31m+       0.upto( self.size - 1 ) do | i |[0m
[31m+ 	unless self[ i ].match( rhs[ i ] )[0m
[31m+ 	  return false[0m
[31m+ 	end[0m
[31m+       end[0m
[31m+       return true[0m
[31m+     end[0m
[31m+   end[0m
  
  
    # SYNOPSIS
    #   1. reader = CSV.open( filename, "r" )
    #
    #   2. CSV.open( filename, "r" ) do | row |
    #        ...
    #      end
    #      
    #   3. writer = CSV.open( filename, "w" )
    #
    #   4. CSV.open( filename, "w" ) do | writer |
    #        ...
    #      end
    #
    # ARGS
    #   filename: filename to open.
    #   mode: "r" for read (parse)
    #         "w" for write (generate)
    #   row: an Array of cells which is a parsed line.
    #   writer: Created writer instance.  See CSV::Writer#<< and
    #     CSV::Writer#addRow to know how to generate CSV string.
    #
    # RETURNS
    #   reader: Create reader instance.  To get parse result, see
    #     CSV::Reader#each.
    #   writer: Created writer instance.  See CSV::Writer#<< and
    #     CSV::Writer#addRow to know how to generate CSV string.
    #
    # DESCRIPTION
    #   Open a CSV formatted file to read or write.
    #
    # EXAMPLE 1
    #   reader = CSV.open( "csvfile.csv", "r" )
    #   row1 = reader.shift
    #   row2 = reader.shift
    #   if row2.empty?
    #     p "row2 not find."
    #   end
    #   reader.close
    #   
    # EXAMPLE 2
    #   CSV.open( "csvfile.csv", "r" ) do | row |
    #     p row
    #   end
    #      
    # EXAMPLE 3
    #   writer = CSV.open( "csvfile.csv", "w" )
    #   writer << [ "r1c1", "r1c2" ] << [ "r2c1", "r2c2" ] << [ nil, nil ]
    #   writer.close
    #   
    # EXAMPLE 4
    #   CSV.open( "csvfile.csv", "w" ) do | writer |
    #     writer << [ "r1c1", "r1c2" ]
    #     writer << [ "r2c1", "r2c2" ]
    #     writer << [ nil, nil ]
    #   end
    #
[31m+   def CSV.open( filename, mode, colSep = ?,, &block )[0m
[31m+     if mode == "r" or mode == "rb"[0m
[31m+       openReader( filename, colSep, &block )[0m
[31m+     elsif mode == "w" or mode == "wb"[0m
[31m+       openWriter( filename, colSep, &block )[0m
[31m+     else[0m
[31m+       raise ArgumentError.new( "'mode' mustbe 'r' or 'w'" )[0m
[31m+     end[0m
[31m+   end[0m
  
    # Private class methods.
[31m+   class << self[0m
[31m+   private[0m
[31m+     def openReader( filename, colSep, &block )[0m
[31m+       file = File.open( filename, "rb" )[0m
[31m+       if block[0m
[31m+ 	begin[0m
[31m+ 	  CSV::Reader.parse( file, colSep ) do | row |[0m
[31m+ 	    yield( row )[0m
[31m+ 	  end[0m
[31m+ 	ensure[0m
[31m+ 	  file.close[0m
[31m+ 	end[0m
[31m+ 	nil[0m
[31m+       else[0m
[31m+ 	reader = CSV::Reader.create( file, colSep )[0m
[31m+ 	reader.closeOnTerminate[0m
[31m+ 	reader[0m
[31m+       end[0m
[31m+     end[0m
  
[31m+     def openWriter( filename, colSep, &block )[0m
[31m+       file = File.open( filename, "wb" )[0m
[31m+       if block[0m
[31m+ 	begin[0m
[31m+ 	  CSV::Writer.generate( file, colSep ) do | writer |[0m
[31m+ 	    yield( writer )[0m
[31m+ 	  end[0m
[31m+ 	ensure[0m
[31m+ 	  file.close[0m
[31m+ 	end[0m
[31m+ 	nil[0m
[31m+       else[0m
[31m+ 	writer = CSV::Writer.create( file, colSep )[0m
[31m+ 	writer.closeOnTerminate[0m
[31m+ 	writer[0m
[31m+       end[0m
[31m+     end[0m
[31m+   end[0m
  
  
    # DESCRIPTION
    #   CSV::Reader -- CSV formatted string/stream reader.
    #   
    # EXAMPLE
    #   Read CSV lines untill the first column is 'stop'.
    #
    #   CSV::Reader.parse( File.open( "bigdata", "rb" )) do | row |
    #     p row
    #     break if !row[ 0 ].isNull && row[ 0 ].data == 'stop'
    #   end
    #
[31m+   class Reader[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   CSV::Reader.parse( stringOrReadable ) do | row |
      #     ...
      #   end
      #
      # ARGS
      #   stringOrReadable: a CSV data to be parsed.  A String or an IO.
      #   row: a CSV::Row; an Array of a CSV::Cell in a line.
      #
      # RETURNS
      #   nil
      #
      # DESCRIPTION
      #   Parse CSV data and get lines.  Caller block is called for each line
      #   with an argument which is a chunk of cells in a row.
      #
      #   Block value is always nil.  Rows are not cached for performance
      #   reason.
      #
[31m+     def Reader.parse( stringOrReadable, colSep = ?, )[0m
[31m+       reader = create( stringOrReadable, colSep )[0m
[31m+       reader.each do | row |[0m
[31m+ 	yield( row )[0m
[31m+       end[0m
[31m+       reader.close[0m
[31m+       nil[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   reader = CSV::Reader.create( stringOrReadable )
      #
      # ARGS
      #   stringOrReadable: a CSV data to be parsed.  A String or an IO.
      #
      # RETURNS
      #   reader: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  To get parse result, see CSV::Reader#each.
      #   
[31m+     def Reader.create( stringOrReadable, colSep = ?, )[0m
[31m+       case stringOrReadable[0m
[31m+       when IO[0m
[31m+ 	IOReader.new( stringOrReadable, colSep )[0m
[31m+       when String[0m
[31m+ 	StringReader.new( stringOrReadable, colSep )[0m
[31m+       else[0m
[31m+ 	IOReader.new( stringOrReadable, colSep )[0m
[31m+       end[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Reader#each do | row |
      #     ...
      #   end
      #
      # ARGS
      #   row: a CSV::Row; an Array of a CSV::Cell in a line.
      #
      # RETURNS
      #   nil
      #
      # DESCRIPTION
      #   Caller block is called for each line with an argument which is a chunk
      #   of cells in a row.
      #
      #   Block value is always nil.  Rows are not cached for performance
      #   reason.
      #   
[31m+     def each[0m
[31m+       while true[0m
[31m+ 	row = Row.new[0m
[31m+ 	nofCells = getRow( row )[0m
[31m+ 	if nofCells == 0[0m
[31m+ 	  break[0m
[31m+ 	end[0m
[31m+ 	yield( row )[0m
[31m+       end[0m
[31m+       nil[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   cell = CSV::Reader#shift
      #
      # RETURNS
      #   cell: a CSV::Row; an Array of a CSV::Cell.
      #
      # DESCRIPTION
      #   Extract cells of next line.
      #   
[31m+     def shift[0m
[31m+       row = Row.new[0m
[31m+       nofCells = getRow( row )[0m
[31m+       row[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Reader#close
      #
      # RETURNS
      #   nil
      #
      # DESCRIPTION
      #   Close this reader.
      #   
[31m+     def close[0m
[31m+       terminate[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def initialize( dev )[0m
[31m+       raise RuntimeError.new( 'Do not instanciate this class directly.' )[0m
[31m+     end[0m
  
[31m+     def getRow( row )[0m
[31m+       raise NotImplementedError.new( 'Method getRow must be defined in a derived class.' )[0m
[31m+     end[0m
  
[31m+     def terminate[0m
        # Define if needed.
      end
    end
    
  
    # DESCRIPTION
    #   CSV::StringReader -- CSV formatted stream reader.
    #   
    # EXAMPLE
    #   Read CSV lines untill the first column is 'stop'.
    #
    #   CSV::Reader.parse( File.open( "bigdata", "rb" )) do | row |
    #     p row
    #     break if !row[ 0 ].isNull && row[ 0 ].data == 'stop'
    #   end
    #
[31m+   class StringReader < Reader[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   reader = CSV::StringReader.new( string )
      #
      # ARGS
      #   string: a CSV String to be parsed.
      #
      # RETURNS
      #   reader: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  To get parse result, see CSV::Reader#each.
      #   
[31m+     def initialize( string, colSep = ?, )[0m
[31m+       @colSep = colSep[0m
[31m+       @dev = string[0m
[31m+       @idx = 0[0m
[31m+       if @dev[0, 3] == "\xef\xbb\xbf"[0m
[31m+ 	@idx += 3[0m
[31m+       end[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def getRow( row )[0m
[31m+       nofCells, nextIdx = CSV.parseLine( @dev, @idx, row, @colSep )[0m
[31m+       if nofCells == 0 && nextIdx == 0 && @idx != @dev.size[0m
[31m+ 	raise IllegalFormatError.new[0m
[31m+       end[0m
[31m+       @idx = nextIdx[0m
[31m+       return nofCells[0m
[31m+     end[0m
[31m+   end[0m
  
  
    # DESCRIPTION
    #   CSV::IOReader -- CSV formatted stream reader.
    #   
    # EXAMPLE
    #   Read CSV lines untill the first column is 'stop'.
    #
    #   CSV::Reader.parse( File.open( "bigdata", "rb" )) do | row |
    #     p row
    #     break if !row[ 0 ].isNull && row[ 0 ].data == 'stop'
    #   end
    #
[31m+   class IOReader < Reader[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   reader = CSV::IOReader.new( io )
      #
      # ARGS
      #   io: a CSV data to be parsed.  Must be an IO. (io#sysread is called.)
      #
      # RETURNS
      #   reader: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  To get parse result, see CSV::Reader#each.
      #   
[31m+     def initialize( io, colSep = ?, )[0m
[31m+       @io = io[0m
[31m+       @colSep = colSep[0m
[31m+       @dev = CSV::IOBuf.new( @io )[0m
[31m+       @idx = 0[0m
[31m+       if @dev[0] == 0xef and @dev[1] == 0xbb and @dev[2] == 0xbf[0m
[31m+ 	@idx += 3[0m
[31m+       end[0m
[31m+       @closeOnTerminate = false[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::IOReader#closeOnTerminate
      #
      # RETURNS
      #   true
      #
      # DESCRIPTION
      #   Tell this reader to close the IO when terminated (Triggered by invoking
      #   CSV::IOReader#close).
      #   
[31m+     def closeOnTerminate[0m
[31m+       @closeOnTerminate = true[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def getRow( row )[0m
[31m+       nofCells, nextIdx = CSV.parseLine( @dev, @idx, row, @colSep )[0m
[31m+       if nofCells == 0 && nextIdx == 0 && !@dev.isEOS?[0m
[31m+ 	raise IllegalFormatError.new[0m
[31m+       end[0m
[31m+       dropped = @dev.drop( nextIdx )[0m
[31m+       @idx = nextIdx - dropped[0m
[31m+       return nofCells[0m
[31m+     end[0m
  
[31m+     def terminate[0m
[31m+       if @closeOnTerminate[0m
[31m+ 	@io.close[0m
[31m+       end[0m
  
[31m+       if @dev[0m
[31m+ 	@dev.close[0m
[31m+       end[0m
[31m+     end[0m
[31m+   end[0m
  
  
    # DESCRIPTION
    #   CSV::Writer -- CSV formatted string/stream writer.
    #   
    # EXAMPLE
    #   Write rows to 'csvout' file.
    #
    #   outfile = File.open( 'csvout', 'wb' )
    #   CSV::Writer.generate( outfile ) do | csv |
    #     csv << [ 'c1', nil, '', '"', "\r\n", 'c2' ]
    #     # or
    #     csv.addRow [
    #       CSV::Cell.new( 'c1', false ),
    #       CSV::Cell.new( 'dummy', true ),
    #       CSV::Cell.new( '', false ),
    #       CSV::Cell.new( '"', false ),
    #       CSV::Cell.new( "\r\n", false )
    #       CSV::Cell.new( "c2", false )
    #     ]
    #     ...
    #     ...
    #   end
    #
    #   outfile.close
    #
[31m+   class Writer[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   CSV::Writer.generate( stringOrWritable ) do | writer |
      #     ...
      #   end
      #
      # ARGS
      #   stringOrWritable: device for generated CSV string.  Must respond to
      #     '<<( aString )'.
      #   writer: Created writer instance.  See CSV::Writer#<< and
      #     CSV::Writer#addRow to know how to generate CSV string.
      #
      # RETURNS
      #   nil
      #
      # DESCRIPTION
      #   Create writer instance.  Caller block is called with the new instance.
      #   To add CSV data to generate CSV string, see CSV::Writer#<< or
      #   CSV::Writer#addRow.
      #   
[31m+     def Writer.generate( stringOrWritable, colSep = ?, )[0m
[31m+       writer = Writer.create( stringOrWritable, colSep )[0m
[31m+       yield( writer )[0m
[31m+       writer.close[0m
[31m+       nil[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   writer = CSV::Writer.create( stringOrReadable )
      #
      # ARGS
      #   stringOrWritable: device for generated CSV string.  Must respond to
      #     '<<( aString )'.
      #
      # RETURNS
      #   writer: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  To add CSV data to generate CSV string, see
      #   CSV::Writer#<< or CSV::Writer#addRow.
      #   
[31m+     def Writer.create( stringOrReadable, colSep = ?, )[0m
[31m+       BasicWriter.new( stringOrReadable, colSep )[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Writer#<<( strArray )
      #
      # ARGS
      #   strArray: an Array of a String.
      #
      # RETURNS
      #   self
      #
      # DESCRIPTION
      #   Dump CSV stream to the device.  Argument is an array of a String like
      #   [ "c1", "c2", "c3" ].
      #   
[31m+     def <<( row )[0m
[31m+       @dev << CSV.create( row, @colSep ) << "\r\n"[0m
[31m+       self[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Writer#<<( cellsArray )
      #
      # ARGS
      #   cellsArray: an Array of a CSV::Cell.
      #
      # RETURNS
      #   self
      #
      # DESCRIPTION
      #   Dump CSV stream to the device.  Argument is an array of a CSV::Cell
      #   like [ CSV::Cell.new( "c1", false ), CSV::Cell.new( "dummy", true ) ].
      #   (Formar is "c1" and latter is Null.)
      #   
[31m+     def addRow( row )[0m
[31m+       CSV.createLine( row, row.size, @dev, @colSep )[0m
[31m+       self[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::Writer#close
      #
      # RETURNS
      #   nil
      #
      # DESCRIPTION
      #   Close this writer.
      #   
[31m+     def close[0m
[31m+       terminate[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def initialize( dev )[0m
[31m+       raise RuntimeError.new( 'Do not instanciate this class directly.' )[0m
[31m+     end[0m
  
[31m+     def terminate[0m
        # Define if needed.
      end
    end
  
  
    # DESCRIPTION
    #   CSV::BasicWriter -- CSV formatted string/stream writer using <<.
    #   
[31m+   class BasicWriter < Writer[0m
[31m+   public[0m
  
      # SYNOPSIS
      #   writer = CSV::BasicWriter.new( stringOrWritable )
      #
      # ARGS
      #   stringOrWritable: device for generated CSV string.  Must respond to
      #     '<<( aString )'.
      #
      # RETURNS
      #   writer: Created instance.
      #
      # DESCRIPTION
      #   Create instance.  To add CSV data to generate CSV string, see
      #   CSV::Writer#<< or CSV::Writer#addRow.
      #   
[31m+     def initialize( stringOrWritable, colSep = ?, )[0m
[31m+       @colSep = colSep[0m
[31m+       @dev = stringOrWritable[0m
[31m+       @closeOnTerminate = false[0m
[31m+     end[0m
  
      # SYNOPSIS
      #   CSV::BasicWriter#closeOnTerminate
      #
      # RETURNS
      #   true
      #
      # DESCRIPTION
      #   Tell this writer to close the IO when terminated (Triggered by invoking
      #   CSV::BasicWriter#close).
      #   
[31m+     def closeOnTerminate[0m
[31m+       @closeOnTerminate = true[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def terminate[0m
[31m+       if @closeOnTerminate[0m
[31m+ 	@dev.close[0m
[31m+       end[0m
[31m+     end[0m
[31m+   end[0m
  
    # SYNOPSIS
    #   cells = CSV.parse( src, colSep = ?, )
    #
    # ARGS
    #   src: a CSV String.
    #   colSep: Column separator.  ?, by default.  If you want to separate
    #     fields with semicolon, give ?; here.
    #
    # RETURNS
    #   cells: an Array of parsed cells in first line.  Each cell is a String.
    #
    # DESCRIPTION
    #   Parse one line from given string.  Bare in mind it parses ONE LINE.  Rest
    #   of the string is ignored for example "a,b\r\nc,d" => [ "a", "b" ] and the
    #   second line "c,d" is ignored.
    #
    #   If you don't know whether a target string to parse is exactly 1 line or
    #   not, use CSV.parseLine instead of this method.
    #   
[31m+   def CSV.parse( src, colSep = ?, )[0m
[31m+     idx = 0[0m
[31m+     resType = :DT_COLSEP[0m
[31m+     cells = Row.new[0m
[31m+     begin[0m
[31m+       while ( resType.equal?( :DT_COLSEP ))[0m
[31m+ 	aCell = Cell.new[0m
[31m+ 	resType, idx = parseBody( src, idx, aCell, colSep )[0m
[31m+ 	cells.push( aCell.isNull ? nil : aCell.data )[0m
[31m+       end[0m
[31m+     rescue IllegalFormatError[0m
[31m+       return Row.new[0m
[31m+     end[0m
[31m+     cells[0m
[31m+   end[0m
    
  
    # SYNOPSIS
    #   str = CSV.create( cells, colSep = ?, )
    #
    # ARGS
    #   cells: an Array of cell to be converted to CSV string.  Each cell must 
    #     respond to 'to_s'.
    #   colSep: Column separator.  ?, by default.  If you want to separate
    #     fields with semicolon, give ?; here.
    #
    # RETURNS
    #   str: a String of generated CSV string.
    #
    # DESCRIPTION
    #   Create a line from cells.  Each cell is stringified by to_s.
    #   
[31m+   def CSV.create( cells, colSep = ?, )[0m
[31m+     if ( cells.size == 0 )[0m
[31m+       return ""[0m
[31m+     end[0m
[31m+     resType = :DT_COLSEP[0m
[31m+     resStr = ""[0m
[31m+     idx = 0[0m
[31m+     while true[0m
[31m+       cell = if ( cells[ idx ].nil? )[0m
[31m+ 	  Cell.new( '', true )[0m
[31m+ 	else[0m
[31m+ 	  Cell.new( cells[ idx ].to_s, false )[0m
[31m+ 	end[0m
[31m+       createBody( cell, resStr, colSep )[0m
[31m+       idx += 1[0m
[31m+       if ( idx == cells.size )[0m
[31m+ 	break[0m
[31m+       end[0m
[31m+       createSeparator( :DT_COLSEP, resStr, colSep )[0m
[31m+     end[0m
[31m+     resStr[0m
[31m+   end[0m
    
    # SYNOPSIS
    #   nofCell, idx = CSV.parseLine( src, idx, outDev, colSep = ?, )
    #
    # ARGS
    #   src: a CSV data to be parsed.  Must respond '[]( idx )'.
    #     src[]( idx ) must return a char. (Not a string such as "a", but 97).
    #     src[]( idxOutOfBounds ) must return nil.  A String satisfies this
    #     requirement.
    #   idx: index of parsing location of 'src'.  0 origin.
    #   outDev: buffer for parsed cells.  Must respond '<<( aCSV::Cell )'.
    #   colSep: Column separator.  ?, by default.  If you want to separate
    #     fields with semicolon, give ?; here.
    #
    # RETURNS
    #   nofCell: num of parsed cells.
    #   idx: index of next parsing location of 'src'.
    #
    # DESCRIPTION
    #   Parse a line from string.  To parse lines in CSV string, see EXAMPLE
    #   below.
    #
    # EXAMPLE
    #   src = "a,b\r\nc,d\r\ne,f"
    #   idx = 0
    #   begin
    #	parsed = []
    #	nofCells, idx = CSV.parseLine( src, idx, parsed )
    #	puts "Parsed #{ nofCells } cells."
    #	p parsed
    #   end while nofCells > 0
    #   
[31m+   def CSV.parseLine( src, idx, outDev, colSep = ?, )[0m
[31m+     idxBack = idx[0m
[31m+     nofCell = 0[0m
[31m+     resType = :DT_COLSEP[0m
[31m+     begin[0m
[31m+       while ( !resType.equal?( :DT_ROWSEP ))[0m
[31m+ 	aCell = Cell.new[0m
[31m+ 	resType, idx = parseBody( src, idx, aCell, colSep )[0m
[31m+ 	if resType.equal?( :DT_EOS )[0m
[31m+ 	  if idx == idxBack #(( nofCell == 0 ) && ( aCell.isNull ))[0m
[31m+ 	    return 0, 0[0m
[31m+ 	  end[0m
[31m+ 	  resType = :DT_ROWSEP[0m
[31m+ 	end[0m
[31m+ 	nofCell += 1[0m
[31m+ 	outDev << aCell[0m
[31m+       end[0m
[31m+     rescue IllegalFormatError[0m
[31m+       return 0, 0[0m
[31m+     end[0m
[31m+     return nofCell, idx[0m
[31m+   end[0m
    
    # SYNOPSIS
    #   nofCells = CSV.createLine( src, cells, outDev, colSep = ?, )
    #
    # ARGS
    #   src: an Array of CSV::Cell to be converted to CSV string.  Must respond to
    #     'size' and '[]( idx )'.  src[ idx ] must return CSV::Cell.
    #   cells: num of cells in a line.
    #   outDev: buffer for created CSV string.  Must respond to '<<( aString )'.
    #   colSep: Column separator.  ?, by default.  If you want to separate
    #     fields with semicolon, give ?; here.
    #
    # RETURNS
    #   nofCells: num of converted cells.
    #
    # DESCRIPTION
    #   Convert a line from cells data to string.  To create multi-row CSV string,
    #   see EXAMPLE below.
    #
    # EXAMPLE
    #   def d( str )
    #     CSV::Cell.new( str, false )
    #   end
    #
    #   row1 = [ d( 'a' ), d( 'b' ) ]
    #   row2 = [ d( 'c' ), d( 'd' ) ]
    #   row3 = [ d( 'e' ), d( 'f' ) ]
    #   src = [ row1, row2, row3 ]
    #   buf = ''
    #   src.each do | row |
    #     nofCells = CSV.createLine( row, 2, buf )
    #     puts "Created #{ nofCells } cells."
    #   end
    #   p buf
    #   
[31m+   def CSV.createLine( src, cells, outDev, colSep = ?, )[0m
[31m+     srcSize = src.size[0m
[31m+     if ( srcSize == 0 )[0m
[31m+       if cells == 0[0m
[31m+ 	createSeparator( :DT_ROWSEP, outDev, colSep )[0m
[31m+       end[0m
[31m+       return 0[0m
[31m+     end[0m
[31m+     resType = :DT_COLSEP[0m
[31m+     nofCells = 0[0m
[31m+     createBody( src[ nofCells ], outDev, colSep )[0m
[31m+     nofCells += 1[0m
[31m+     while (( nofCells < cells ) && ( nofCells != srcSize ))[0m
[31m+       createSeparator( :DT_COLSEP, outDev, colSep )[0m
[31m+       createBody( src[ nofCells ], outDev, colSep )[0m
[31m+       nofCells += 1[0m
[31m+     end[0m
[31m+     if ( nofCells == cells )[0m
[31m+       createSeparator( :DT_ROWSEP, outDev, colSep )[0m
[31m+     else[0m
[31m+       createSeparator( :DT_COLSEP, outDev, colSep )[0m
[31m+     end[0m
[31m+     nofCells[0m
[31m+   end[0m
    
[31m+   private[0m
[31m+   class IllegalFormatError < RuntimeError; end[0m
  
    # Private class methods.
[31m+   class << self[0m
[31m+   private[0m
  
[31m+     def parseBody( src, idx, aCell, colSep )[0m
[31m+       aCell.isNull = false[0m
[31m+       state = :ST_START[0m
[31m+       quoted = false[0m
[31m+       cr = false[0m
[31m+       c = nil[0m
[31m+       while ( c = src[ idx ] )[0m
[31m+ 	idx += 1[0m
[31m+ 	resultState = :DT_UNKNOWN[0m
[31m+ 	if ( c == colSep )[0m
[31m+ 	  if state.equal?( :ST_DATA )[0m
[31m+ 	    if cr[0m
[31m+ 	      raise IllegalFormatError.new[0m
[31m+ 	    end[0m
[31m+ 	    if ( !quoted )[0m
[31m+ 	      state = :ST_END[0m
[31m+ 	      resultState = :DT_COLSEP[0m
[31m+ 	    else[0m
[31m+ 	      aCell.data << c.chr[0m
[31m+ 	    end[0m
[31m+ 	  elsif state.equal?( :ST_QUOTE )[0m
[31m+ 	    if cr[0m
[31m+ 	      raise IllegalFormatError.new[0m
[31m+ 	    end[0m
[31m+ 	    state = :ST_END[0m
[31m+ 	    resultState = :DT_COLSEP[0m
[31m+ 	  else	# :ST_START[0m
[31m+ 	    aCell.isNull = true[0m
[31m+ 	    state = :ST_END[0m
[31m+ 	    resultState = :DT_COLSEP[0m
[31m+ 	  end[0m
[31m+ 	elsif ( c == ?" )		# " for vim syntax hilighting.[0m
[31m+ 	  if state.equal?( :ST_DATA )[0m
[31m+ 	    if cr[0m
[31m+ 	      raise IllegalFormatError.new[0m
[31m+ 	    end[0m
[31m+ 	    if quoted[0m
[31m+ 	      quoted = false[0m
[31m+ 	      state = :ST_QUOTE[0m
[31m+ 	    else[0m
[31m+ 	      raise IllegalFormatError.new[0m
[31m+ 	    end[0m
[31m+ 	  elsif state.equal?( :ST_QUOTE )[0m
[31m+ 	    aCell.data << c.chr[0m
[31m+ 	    quoted = true[0m
[31m+ 	    state = :ST_DATA[0m
[31m+ 	  else	# :ST_START[0m
[31m+ 	    quoted = true[0m
[31m+ 	    state = :ST_DATA[0m
[31m+ 	  end[0m
[31m+ 	elsif ( c == ?\r )[0m
[31m+ 	  if cr[0m
[31m+ 	    raise IllegalFormatError.new[0m
[31m+ 	  end[0m
[31m+ 	  if quoted[0m
[31m+ 	    aCell.data << c.chr[0m
[31m+ 	    state = :ST_DATA[0m
[31m+ 	  else[0m
[31m+ 	    cr = true[0m
[31m+ 	  end[0m
[31m+ 	elsif ( c == ?\n )[0m
[31m+ 	  if state.equal?( :ST_DATA )[0m
[31m+ 	    if cr[0m
[31m+ 	      state = :ST_END[0m
[31m+ 	      resultState = :DT_ROWSEP[0m
[31m+ 	      cr = false[0m
[31m+ 	    else[0m
[31m+ 	      if quoted[0m
[31m+ 		aCell.data << c.chr[0m
[31m+ 		state = :ST_DATA[0m
[31m+ 	      else[0m
[31m+ 		state = :ST_END[0m
[31m+ 		resultState = :DT_ROWSEP[0m
[31m+ 	      end[0m
[31m+ 	    end[0m
[31m+ 	  elsif state.equal?( :ST_QUOTE )[0m
[31m+ 	    state = :ST_END[0m
[31m+ 	    resultState = :DT_ROWSEP[0m
[31m+ 	    if cr[0m
[31m+ 	      cr = false[0m
[31m+ 	    end[0m
[31m+ 	  else	# :ST_START[0m
[31m+ 	    aCell.isNull = true[0m
[31m+ 	    state = :ST_END[0m
[31m+     	    resultState = :DT_ROWSEP[0m
[31m+ 	  end[0m
[31m+ 	else[0m
[31m+ 	  if state.equal?( :ST_DATA ) || state.equal?( :ST_START )[0m
[31m+ 	    if cr[0m
[31m+ 	      raise IllegalFormatError.new[0m
[31m+ 	    end[0m
[31m+ 	    aCell.data << c.chr[0m
[31m+ 	    state = :ST_DATA[0m
[31m+ 	  else	# :ST_QUOTE[0m
[31m+ 	    raise IllegalFormatError.new[0m
[31m+ 	  end[0m
[31m+ 	end[0m
[31m+ 	if state.equal?( :ST_END )[0m
[31m+ 	  return resultState, idx;[0m
[31m+ 	end[0m
[31m+       end[0m
[31m+       if state.equal?( :ST_START )[0m
[31m+ 	aCell.isNull = true[0m
[31m+       elsif state.equal?( :ST_QUOTE )[0m
[31m+ 	true	# dummy for coverate; only a data[0m
[31m+       elsif quoted[0m
[31m+        	raise IllegalFormatError.new[0m
[31m+       elsif cr[0m
[31m+        	raise IllegalFormatError.new[0m
[31m+       end[0m
[31m+       return :DT_EOS, idx[0m
[31m+     end[0m
    
[31m+     def createBody( cellData, outDev, colSep )[0m
[31m+       addData = cellData.data.dup[0m
[31m+       if ( !cellData.isNull )[0m
         	if ( addData.gsub!( '"', '""' ) ||
[31m+ 	    addData.include?( colSep ) ||[0m
[31m+   	    ( /[\r\n]/ =~ addData ) || ( cellData.data.empty? ))[0m
[31m+   	  outDev << '"' << addData << '"'[0m
[31m+    	else[0m
[31m+   	  outDev << addData[0m
[31m+    	end[0m
[31m+       end[0m
[31m+     end[0m
      
[31m+     def createSeparator( type, outDev, colSep )[0m
[31m+       case type[0m
[31m+       when :DT_COLSEP[0m
[31m+        	outDev << colSep.chr[0m
[31m+       when :DT_ROWSEP[0m
[31m+ 	outDev << "\r\n"[0m
[31m+       end[0m
[31m+     end[0m
[31m+   end[0m
  
  
    # DESCRIPTION
    #   CSV::StreamBuf -- a class for a bufferd stream.
    #
    # EXAMPLE 1 -- an IO.
    #   class MyBuf < StreamBuf
    #     # Do initialize myself before a super class.  Super class might call my
    #     # method 'read'. (Could be awful for C++ user. :-)
    #     def initialize( s )
    #       @s = s
    #       super()
    #     end
    #
    #     # define my own 'read' method.
    #     # CAUTION: Returning a string which size is not equal to 'size' means
    #     #   EnfOfStream.
    #     def read( size )
    #       @s.sysread( size )
    #     end
    #
    #     # release buffers. in Ruby which has GC, you do not have to call this...
    #     def terminate
    #       @s = nil
    #       super()
    #     end
    #   end
    #
    #   aBuf = MyBuf.new( STDIN )
    #   myStr = ""
    #   p aBuf[0, 0]		# => "" ( null string )
    #   p aBuf[0]			# => 97 ( char code of 'a' )
    #   p aBuf[0, 1]		# => "a"
    #   myStr = aBuf[0, 5]
    #   p myStr			# => "abcde" ( 5 chars )
    #   p aBuf[0, 6]		# => "abcde\n" ( 6 chars )
    #   p aBuf[0, 7]		# => "abcde\n" ( 6 chars )
    #   p aBuf.drop( 3 )		# => 3 ( dropped chars )
    #   p aBuf.get(0, 2)		# => "de" ( 2 chars )
    #   p aBuf.isEOS?		# => false ( is not EOS here )
    #   p aBuf.drop( 5 )		# => 3 ( dropped chars )
    #   p aBuf.isEOS?		# => true ( is EOS here )
    #   p aBuf[0]			# => nil ( is EOS here )
    #
    # EXAMPLE 2 -- String.
    #   This is a conceptual example.  No pros with this.
    # 
    #   class StrBuf < StreamBuf
    #     def initialize( s )
    #       @str = s
    #       @idx = 0
    #       super()
    #     end
    #   
    #     def read( size )
    #       str = @str[ @idx, size ]
    #       @idx += str.size
    #       str
    #     end
    #   end
    #
[31m+   class StreamBuf	# pure virtual. (do not instanciate it directly)[0m
[31m+   public[0m
    
      # SYNOPSIS
      #   char/str = CSV::StreamBuf#get( idx, n = nil )
      #   char/str = CSV::StreamBuf#[ idx, n = nil ]
      #
      # ARGS
      #   idx: index of a string to specify a start point of a string to get.
      #     Unlike String instance, idx < 0 returns nil.
      #   n: size of a string to get.
      #
      # RETURNS
      #   char: if n == nil.  A char at idx.
      #   str: if n != nil.  A partial string, from idx to ( idx + size ).  At
      #     EOF, the string size could not equal to arg n.
      #
      # DESCRIPTION
      #   Get a char or a partial string from the stream.
      #
[31m+     def []( idx, n = nil ) [0m
[31m+       if idx < 0[0m
[31m+ 	return nil[0m
[31m+       end[0m
[31m+       if ( idxIsEOS?( idx ))[0m
[31m+ 	if n and ( @offset + idx == @maxIdx )[0m
  	  # Like a String, "abc"[ 4, 1 ] returns nil and
  	  # "abc"[ 3, 1 ] returns "", not nil.
[31m+ 	  return ""[0m
[31m+ 	else[0m
[31m+ 	  return nil[0m
[31m+ 	end[0m
[31m+       end[0m
[31m+       myBuf = @curBuf[0m
[31m+       myOffset = @offset[0m
[31m+       nextIdx = idx[0m
[31m+       while ( myOffset + nextIdx >= BufSize )[0m
[31m+ 	if ( myBuf == @bufTailIdx )[0m
[31m+ 	  unless addBuf[0m
[31m+ 	    break[0m
[31m+ 	  end[0m
[31m+ 	end[0m
[31m+ 	myBuf += 1[0m
[31m+ 	nextIdx = myOffset + nextIdx - BufSize[0m
[31m+ 	myOffset = 0[0m
[31m+       end[0m
[31m+       if ( @isEOS && ( myBuf == @bufTailIdx ) &&[0m
[31m+   	  ( myOffset + nextIdx > @maxIdx ))[0m
[31m+ 	return nil[0m
[31m+       end[0m
[31m+       if !n[0m
[31m+ 	return @bufList[ myBuf ][ myOffset + nextIdx ]	# Fixnum of char code.[0m
[31m+       elsif ( myOffset + nextIdx + n - 1 < BufSize )[0m
[31m+ 	return @bufList[ myBuf ][ myOffset + nextIdx, n ]	# String.[0m
        else
  	# should do loop insted of (tail) recursive call...
[31m+ 	res = @bufList[ myBuf ][ myOffset + nextIdx..-1 ][0m
[31m+ 	addSize = BufSize - ( myOffset + nextIdx )[0m
[31m+ 	idx += addSize[0m
[31m+ 	n -= addSize[0m
[31m+ 	ret = self[ idx, n ][0m
[31m+ 	if ret[0m
[31m+ 	  res << ret[0m
[31m+ 	end[0m
[31m+ 	return res[0m
[31m+       end[0m
[31m+     end[0m
[31m+     alias get [][0m
    
      # SYNOPSIS
      #   dropSize = CSV::StreamBuf#drop( n )
      #
      # ARGS
      #   n: drop size
      #
      # RETURNS
      #   dropSize: droped size.  At EOF, dropped size might not equals to arg n.
      #     0 if n <= 0.
      #
      # DESCRIPTION
      #   Drop a string from the stream.  Once you drop the head of the stream,
      #   access to the dropped part via [] or get returns nil.
      #
[31m+     def drop( n )[0m
[31m+       if isEOS?[0m
[31m+ 	return 0[0m
[31m+       end[0m
[31m+       dropSize = 0[0m
[31m+       while ( n > 0 )[0m
[31m+ 	if ( @isEOS && ( @curBuf == @bufTailIdx ))[0m
[31m+ 	  if ( @offset + n < @maxIdx )[0m
[31m+ 	    dropSize += n[0m
[31m+ 	    @offset += n[0m
[31m+ 	    n = 0[0m
[31m+ 	  else[0m
[31m+ 	    dropSize += ( @maxIdx - @offset )[0m
[31m+ 	    n = 0[0m
[31m+ 	    @offset = 0[0m
[31m+ 	    relBuf[0m
[31m+ 	  end[0m
[31m+ 	else[0m
[31m+ 	  if ( @offset + n < BufSize )[0m
[31m+ 	    dropSize += n[0m
[31m+ 	    @offset += n[0m
[31m+ 	    n = 0[0m
[31m+ 	  else[0m
[31m+ 	    dropSize += ( BufSize - @offset )[0m
[31m+ 	    n -= ( BufSize - @offset )[0m
[31m+ 	    @offset = 0[0m
[31m+ 	    unless relBuf[0m
[31m+ 	      unless addBuf[0m
  		break
  	      end
[31m+ 	      @curBuf = @bufTailIdx[0m
[31m+ 	    end[0m
[31m+ 	  end[0m
[31m+ 	end[0m
[31m+       end[0m
[31m+       dropSize[0m
[31m+     end[0m
    
      # SYNOPSIS
      #   eofP = CSV::StreamBuf#isEOS?
      #
      # RETURNS
      #   eofP: true if end of the stream or false.
      #
      # DESCRIPTION
      #   Check EOF or not.
      #
[31m+     def isEOS?[0m
[31m+       return idxIsEOS?( 0 )[0m
[31m+     end[0m
    
      # SYNOPSIS
      #   N/A
      #
      # DESCRIPTION
      #   Do not instanciate this class directly.  Define your own class which
      #   derives this class and define 'read' instance method.
      #
[31m+     def initialize[0m
[31m+       @bufList = [][0m
[31m+       @curBuf = @bufTailIdx = -1[0m
[31m+       @offset = @maxIdx = 0[0m
[31m+       @isEOS = false[0m
[31m+       unless addBuf[0m
  	raise RuntimeError.new( "Couldn't read any buffer..." )
        end
[31m+       @curBuf = @bufTailIdx[0m
[31m+     end[0m
    
[31m+   protected[0m
[31m+     def terminate[0m
[31m+       while ( relBuf ); end[0m
[31m+     end[0m
    
      # protected method 'read' must be defined in derived classes.
      # CAUTION: Returning a string which size is not equal to 'size' means
      #   EnfOfStream.  When it is not at EOS, you must block the callee, try to
      #   read and return the sized string.
[31m+     def read( size ) # raise EOFError[0m
[31m+       raise NotImplementedError.new( 'Method read must be defined in a derived class.' )[0m
[31m+     end[0m
    
[31m+   private[0m
    
[31m+     def addBuf[0m
[31m+       if @isEOS[0m
[31m+ 	return false[0m
[31m+       end[0m
[31m+       begin[0m
[31m+ 	readStr = read( BufSize )[0m
[31m+       rescue EOFError[0m
[31m+ 	readStr = ""[0m
        rescue
[31m+ 	terminate[0m
[31m+ 	raise[0m
[31m+       end[0m
[31m+       rSize = readStr.size[0m
[31m+       if ( rSize != BufSize )[0m
[31m+ 	@isEOS = true[0m
[31m+ 	@maxIdx = rSize[0m
[31m+       end[0m
[31m+       if ( rSize == 0 )[0m
[31m+ 	readStr = ""[0m
[31m+       end[0m
[31m+       @bufList.push( readStr )[0m
[31m+       @bufTailIdx += 1[0m
[31m+       true[0m
[31m+     end[0m
    
[31m+     def relBuf[0m
[31m+       if ( @curBuf < 0 )[0m
[31m+ 	return false[0m
[31m+       end[0m
[31m+       @bufList[ @curBuf ] = nil[0m
[31m+       if ( @curBuf == @bufTailIdx )[0m
[31m+ 	@curBuf = -1[0m
[31m+ 	return false[0m
[31m+       else[0m
[31m+ 	@curBuf += 1[0m
[31m+ 	return true[0m
[31m+       end[0m
[31m+     end[0m
    
[31m+     def idxIsEOS?( idx )[0m
[31m+       ( @isEOS && (( @curBuf < 0 ) || ( @curBuf == @bufTailIdx ) &&[0m
[31m+ 	( @offset + idx >= @maxIdx )))[0m
[31m+     end[0m
    
[31m+     BufSize = 1024 * 100[0m
[31m+   end[0m
  
    # DESCRIPTION
    #   CSV::IOBuf -- a class for a bufferd IO.
    #
    # EXAMPLE
    #   # File 'bigdata' could be a giga-byte size one!
    #   buf = CSV::IOBuf.new( File.open( "bigdata", "rb" ))
    #   CSV::Reader.new( buf ).each do | row |
    #     p row
    #     break if row[ 0 ].data == "admin"
    #   end
    #
[31m+   class IOBuf < StreamBuf[0m
[31m+   public[0m
[31m+     def initialize( s )[0m
[31m+       @s = s[0m
[31m+       super()[0m
[31m+     end[0m
    
[31m+     def close[0m
[31m+       terminate[0m
[31m+     end[0m
  
[31m+   private[0m
[31m+     def read( size )[0m
[31m+       @s.sysread( size )[0m
[31m+     end[0m
   
[31m+     def terminate[0m
[31m+       super()[0m
[31m+     end[0m
[31m+   end[0m
[31m+ end[0m
